Merge pull request #10465 from colinux/attestations-v2-prod
ETQ admin je peux activer la délivrance des attestations v2 (sous feature flag)
This commit is contained in:
commit
ccf5b255ed
42 changed files with 724 additions and 258 deletions
|
@ -623,40 +623,10 @@ textarea::placeholder {
|
|||
color: $dark-grey;
|
||||
}
|
||||
|
||||
@media (max-width: 62em) {
|
||||
|
||||
.padded-fixed-footer {
|
||||
padding-top: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 62em) {
|
||||
|
||||
.padded-fixed-footer {
|
||||
padding-top: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
[data-fr-theme="dark"] .fixed-footer {
|
||||
border-top: 2px solid var(--background-action-low-blue-france-hover);
|
||||
background-color: var(--background-action-low-blue-france);
|
||||
}
|
||||
|
||||
.mandatory {
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.fixed-footer {
|
||||
border-top: 2px solid $blue-france-500;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-top: $default-padding;
|
||||
background-color: $white;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.fr-menu__list {
|
||||
padding: $default-spacer;
|
||||
overflow-y: auto;
|
||||
|
|
49
app/assets/stylesheets/sticky.scss
Normal file
49
app/assets/stylesheets/sticky.scss
Normal file
|
@ -0,0 +1,49 @@
|
|||
@import "constants";
|
||||
|
||||
.fixed-footer {
|
||||
border-top: 2px solid var(--border-plain-blue-france);
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-top: $default-padding;
|
||||
background-color: var(--background-default-grey);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@media (max-width: 62em) {
|
||||
.padded-fixed-footer {
|
||||
padding-top: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 62em) {
|
||||
.padded-fixed-footer {
|
||||
padding-top: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
[data-fr-theme="dark"] .fixed-footer {
|
||||
background-color: var(--background-action-low-blue-france);
|
||||
}
|
||||
|
||||
.sticky-header {
|
||||
padding-top: $default-padding;
|
||||
padding-bottom: $default-padding;
|
||||
|
||||
&-container {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 800;
|
||||
}
|
||||
|
||||
&-warning {
|
||||
background-color: var(--background-contrast-warning);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
16
app/components/autosave_notice_component.rb
Normal file
16
app/components/autosave_notice_component.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AutosaveNoticeComponent < ApplicationComponent
|
||||
attr_reader :label_scope
|
||||
|
||||
def initialize(success:, label_scope:)
|
||||
@success = success
|
||||
@label_scope = label_scope
|
||||
end
|
||||
|
||||
def success? = @success
|
||||
|
||||
def label
|
||||
success? ? t(".#{label_scope}.saved") : t(".#{label_scope}.error")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
en:
|
||||
form:
|
||||
saved: 'Form saved'
|
||||
error: 'Form in error'
|
||||
attestation:
|
||||
saved: 'Attestation saved'
|
||||
error: 'Attestation in error'
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
fr:
|
||||
form:
|
||||
saved: 'Formulaire enregistré'
|
||||
error: 'Formulaire en erreur'
|
||||
attestation:
|
||||
saved: 'Attestation enregistrée'
|
||||
error: 'Attestation en erreur'
|
|
@ -0,0 +1,2 @@
|
|||
#autosave-notice.fr-badge.fr-badge--sm{ class: class_names("fr-badge--success" => success?, "fr-badge--error" => !success?) }
|
||||
= label
|
|
@ -26,6 +26,8 @@ class Dsfr::CalloutComponent < ApplicationComponent
|
|||
"fr-callout--brown-caramel"
|
||||
when :success
|
||||
"fr-callout--green-emeraude"
|
||||
when :neutral
|
||||
# default
|
||||
else
|
||||
"fr-background-alt--blue-france"
|
||||
end
|
||||
|
|
|
@ -98,9 +98,7 @@ module Dsfr
|
|||
})
|
||||
end
|
||||
|
||||
if autoresize?
|
||||
@opts.deep_merge!(data: { controller: 'autoresize' })
|
||||
end
|
||||
@opts.deep_merge!(data: { controller: token_list(@opts.dig(:data, :controller), 'autoresize' => autoresize?) })
|
||||
|
||||
@opts
|
||||
end
|
||||
|
|
|
@ -5,6 +5,14 @@ class Procedure::Card::AttestationComponent < ApplicationComponent
|
|||
|
||||
private
|
||||
|
||||
def edit_attestation_path
|
||||
if @procedure.attestation_templates_v2.any? || @procedure.feature_enabled?(:attestation_v2)
|
||||
helpers.edit_admin_procedure_attestation_template_v2_path(@procedure)
|
||||
else
|
||||
helpers.edit_admin_procedure_attestation_template_path(@procedure)
|
||||
end
|
||||
end
|
||||
|
||||
def error_messages
|
||||
@procedure.errors.messages_for(:attestation_template).to_sentence
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to edit_admin_procedure_attestation_template_path(@procedure), class: 'fr-tile fr-enlarge-link' do
|
||||
= link_to edit_attestation_path, class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.attestation_template&.activated?
|
||||
%div
|
||||
|
|
|
@ -20,27 +20,9 @@ module Administrateurs
|
|||
format.pdf do
|
||||
html = render_to_string('/administrateurs/attestation_template_v2s/show', layout: 'attestation', formats: [:html])
|
||||
|
||||
headers = {
|
||||
'Content-Type' => 'application/json',
|
||||
'X-Request-Id' => Current.request_id
|
||||
}
|
||||
pdf = WeasyprintService.generate_pdf(html, procedure_id: @procedure.id, path: request.path, user_id: current_user.id)
|
||||
|
||||
body = {
|
||||
html: html,
|
||||
upstream_context: {
|
||||
procedure_id: @procedure.id,
|
||||
path: request.path,
|
||||
user_id: current_user.id
|
||||
}
|
||||
}.to_json
|
||||
|
||||
response = Typhoeus.post(WEASYPRINT_URL, headers:, body:)
|
||||
|
||||
if response.success?
|
||||
send_data(response.body, filename: 'attestation.pdf', type: 'application/pdf', disposition: 'inline')
|
||||
else
|
||||
raise StandardError.new("PDF Generation failed: #{response.return_code} #{response.status_message}")
|
||||
end
|
||||
send_data(pdf, filename: 'attestation.pdf', type: 'application/pdf', disposition: 'inline')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -77,6 +59,19 @@ module Administrateurs
|
|||
|
||||
def update
|
||||
attestation_params = editor_params
|
||||
|
||||
# toggle activation
|
||||
if @attestation_template.persisted? && @attestation_template.activated? != cast_bool(attestation_params[:activated])
|
||||
@procedure.attestation_templates.v2.update_all(activated: attestation_params[:activated])
|
||||
render :update && return
|
||||
end
|
||||
|
||||
if @attestation_template.published? && should_edit_draft?
|
||||
@attestation_template = @attestation_template.dup
|
||||
@attestation_template.state = :draft
|
||||
@attestation_template.procedure = @procedure
|
||||
end
|
||||
|
||||
logo_file = attestation_params.delete(:logo)
|
||||
signature_file = attestation_params.delete(:signature)
|
||||
|
||||
|
@ -88,15 +83,40 @@ module Administrateurs
|
|||
attestation_params[:signature] = uninterlace_png(signature_file)
|
||||
end
|
||||
|
||||
if !@attestation_template.update(attestation_params)
|
||||
flash.alert = "Le modèle de l’attestation contient des erreurs et n'a pas pu être enregistré. Corriger les erreurs."
|
||||
end
|
||||
@attestation_template.assign_attributes(attestation_params)
|
||||
|
||||
render :update
|
||||
if @attestation_template.invalid?
|
||||
flash.alert = "L’attestation contient des erreurs et n'a pas pu être enregistrée. Corriger les erreurs."
|
||||
else
|
||||
# - draft just published
|
||||
if @attestation_template.published? && should_edit_draft?
|
||||
published = @procedure.attestation_templates.published
|
||||
|
||||
@attestation_template.transaction do
|
||||
were_published = published.destroy_all
|
||||
@attestation_template.save!
|
||||
flash.notice = were_published.any? ? "La nouvelle version de l’attestation a été publiée." : "L’attestation a été publiée."
|
||||
end
|
||||
|
||||
redirect_to edit_admin_procedure_attestation_template_v2_path(@procedure)
|
||||
else
|
||||
# - draft updated
|
||||
# - or, attestation already published, without need for publication (draft procedure)
|
||||
@attestation_template.save!
|
||||
render :update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create = update
|
||||
|
||||
def reset
|
||||
@procedure.attestation_templates_v2.draft&.destroy_all
|
||||
|
||||
flash.notice = "Les modifications ont été réinitialisées."
|
||||
redirect_to edit_admin_procedure_attestation_template_v2_path(@procedure)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_feature_active
|
||||
|
@ -104,11 +124,19 @@ module Administrateurs
|
|||
end
|
||||
|
||||
def retrieve_attestation_template
|
||||
@attestation_template = @procedure.attestation_template_v2 || @procedure.build_attestation_template_v2(json_body: AttestationTemplate::TIPTAP_BODY_DEFAULT)
|
||||
v2s = @procedure.attestation_templates_v2
|
||||
@attestation_template = v2s.find(&:draft?) || v2s.find(&:published?) || build_default_attestation
|
||||
end
|
||||
|
||||
def build_default_attestation
|
||||
state = should_edit_draft? ? :draft : :published
|
||||
@procedure.build_attestation_template(version: 2, json_body: AttestationTemplate::TIPTAP_BODY_DEFAULT, activated: true, state:)
|
||||
end
|
||||
|
||||
def should_edit_draft? = !@procedure.brouillon?
|
||||
|
||||
def editor_params
|
||||
params.required(:attestation_template).permit(:official_layout, :label_logo, :label_direction, :tiptap_body, :footer, :logo, :signature, :activated)
|
||||
params.required(:attestation_template).permit(:activated, :official_layout, :label_logo, :label_direction, :tiptap_body, :footer, :logo, :signature, :activated, :state)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -112,7 +112,7 @@ module Administrateurs
|
|||
revision_types_de_champ: { type_de_champ: { piece_justificative_template_attachment: :blob } }
|
||||
},
|
||||
attestation_template_v1: [],
|
||||
attestation_template_v2: [],
|
||||
attestation_templates_v2: [],
|
||||
initiated_mail: [],
|
||||
received_mail: [],
|
||||
closed_mail: [],
|
||||
|
|
|
@ -30,9 +30,10 @@ module Instructeurs
|
|||
end
|
||||
|
||||
def apercu_attestation
|
||||
@attestation = dossier.attestation_template.render_attributes_for(dossier: dossier)
|
||||
|
||||
render 'administrateurs/attestation_templates/show', formats: [:pdf]
|
||||
send_data dossier.attestation_template.send(:build_pdf, dossier),
|
||||
filename: 'attestation.pdf',
|
||||
type: 'application/pdf',
|
||||
disposition: 'inline'
|
||||
end
|
||||
|
||||
def bilans_bdf
|
||||
|
|
43
app/javascript/controllers/sticky_top_controller.ts
Normal file
43
app/javascript/controllers/sticky_top_controller.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { ApplicationController } from './application_controller';
|
||||
|
||||
export class StickyTopController extends ApplicationController {
|
||||
// Ajusts top of sticky top components when there is a sticky header.
|
||||
|
||||
connect(): void {
|
||||
const header = document.getElementById('sticky-header');
|
||||
|
||||
if (!header) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.adjustTop(header);
|
||||
|
||||
window.addEventListener('resize', () => this.adjustTop(header));
|
||||
|
||||
this.listenHeaderMutations(header);
|
||||
}
|
||||
|
||||
private listenHeaderMutations(header: HTMLElement) {
|
||||
const config = { childList: true, subtree: true };
|
||||
|
||||
const callback: MutationCallback = (mutationsList) => {
|
||||
for (const mutation of mutationsList) {
|
||||
if (mutation.type === 'childList') {
|
||||
this.adjustTop(header);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const observer = new MutationObserver(callback);
|
||||
observer.observe(header, config);
|
||||
}
|
||||
|
||||
private adjustTop(header: HTMLElement) {
|
||||
const headerHeight = header.clientHeight;
|
||||
|
||||
if (headerHeight > 0) {
|
||||
(this.element as HTMLElement).style.top = `${headerHeight + 8}px`;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,11 +2,16 @@ class AttestationTemplate < ApplicationRecord
|
|||
include ActionView::Helpers::NumberHelper
|
||||
include TagsSubstitutionConcern
|
||||
|
||||
belongs_to :procedure, inverse_of: :attestation_template_v2
|
||||
belongs_to :procedure, inverse_of: :attestation_template
|
||||
|
||||
has_one_attached :logo
|
||||
has_one_attached :signature
|
||||
|
||||
enum state: {
|
||||
draft: 'draft',
|
||||
published: 'published'
|
||||
}
|
||||
|
||||
validates :title, tags: true, if: -> { procedure.present? && version == 1 }
|
||||
validates :body, tags: true, if: -> { procedure.present? && version == 1 }
|
||||
validates :json_body, tags: true, if: -> { procedure.present? && version == 2 }
|
||||
|
@ -67,9 +72,10 @@ class AttestationTemplate < ApplicationRecord
|
|||
}.freeze
|
||||
|
||||
def attestation_for(dossier)
|
||||
attestation = Attestation.new(title: replace_tags(title, dossier, escape: false))
|
||||
attestation = Attestation.new
|
||||
attestation.title = replace_tags(title, dossier, escape: false) if version == 1
|
||||
attestation.pdf.attach(
|
||||
io: build_pdf(dossier),
|
||||
io: StringIO.new(build_pdf(dossier)),
|
||||
filename: "attestation-dossier-#{dossier.id}.pdf",
|
||||
content_type: 'application/pdf',
|
||||
# we don't want to run virus scanner on this file
|
||||
|
@ -91,7 +97,7 @@ class AttestationTemplate < ApplicationRecord
|
|||
end
|
||||
|
||||
def dup
|
||||
attestation_template = AttestationTemplate.new(title: title, body: body, footer: footer, activated: activated)
|
||||
attestation_template = super
|
||||
ClonePiecesJustificativesService.clone_attachments(self, attestation_template)
|
||||
attestation_template
|
||||
end
|
||||
|
@ -179,7 +185,7 @@ class AttestationTemplate < ApplicationRecord
|
|||
|
||||
if dossier.present?
|
||||
# 2x faster this way than with `replace_tags` which would reparse text
|
||||
used_tags = tiptap.used_tags_and_libelle_for(json.deep_symbolize_keys)
|
||||
used_tags = TiptapService.used_tags_and_libelle_for(json.deep_symbolize_keys)
|
||||
substitutions = tags_substitutions(used_tags, dossier, escape: false)
|
||||
body = tiptap.to_html(json, substitutions)
|
||||
|
||||
|
@ -202,17 +208,41 @@ class AttestationTemplate < ApplicationRecord
|
|||
end
|
||||
|
||||
def used_tags
|
||||
used_tags_for(title) + used_tags_for(body)
|
||||
if version == 2
|
||||
json = json_body&.deep_symbolize_keys
|
||||
TiptapService.used_tags_and_libelle_for(json.deep_symbolize_keys).map(&:first)
|
||||
else
|
||||
used_tags_for(title) + used_tags_for(body)
|
||||
end
|
||||
end
|
||||
|
||||
def build_pdf(dossier)
|
||||
if version == 2
|
||||
build_v2_pdf(dossier)
|
||||
else
|
||||
build_v1_pdf(dossier)
|
||||
end
|
||||
end
|
||||
|
||||
def build_v1_pdf(dossier)
|
||||
attestation = render_attributes_for(dossier: dossier)
|
||||
attestation_view = ApplicationController.render(
|
||||
ApplicationController.render(
|
||||
template: 'administrateurs/attestation_templates/show',
|
||||
formats: :pdf,
|
||||
assigns: { attestation: attestation }
|
||||
)
|
||||
end
|
||||
|
||||
StringIO.new(attestation_view)
|
||||
def build_v2_pdf(dossier)
|
||||
body = render_attributes_for(dossier:).fetch(:body)
|
||||
|
||||
html = ApplicationController.render(
|
||||
template: '/administrateurs/attestation_template_v2s/show',
|
||||
formats: [:html],
|
||||
layout: 'attestation',
|
||||
assigns: { attestation_template: self, body: body }
|
||||
)
|
||||
|
||||
WeasyprintService.generate_pdf(html, { procedure_id: procedure.id, dossier_id: dossier.id })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -257,7 +257,7 @@ module TagsSubstitutionConcern
|
|||
def used_type_de_champ_tags(text_or_tiptap)
|
||||
used_tags =
|
||||
if text_or_tiptap.respond_to?(:deconstruct_keys) # hash pattern matching
|
||||
TiptapService.new.used_tags_and_libelle_for(text_or_tiptap.deep_symbolize_keys)
|
||||
TiptapService.used_tags_and_libelle_for(text_or_tiptap.deep_symbolize_keys)
|
||||
else
|
||||
used_tags_and_libelle_for(text_or_tiptap.to_s)
|
||||
end
|
||||
|
|
|
@ -66,11 +66,10 @@ class ExportTemplate < ApplicationRecord
|
|||
end
|
||||
|
||||
def render_attributes_for(content_for, dossier, attachment = nil)
|
||||
tiptap = TiptapService.new
|
||||
used_tags = tiptap.used_tags_and_libelle_for(content_for.deep_symbolize_keys)
|
||||
used_tags = TiptapService.used_tags_and_libelle_for(content_for.deep_symbolize_keys)
|
||||
substitutions = tags_substitutions(used_tags, dossier, escape: false, memoize: true)
|
||||
substitutions['original-filename'] = attachment.filename.base if attachment
|
||||
tiptap.to_path(content_for.deep_symbolize_keys, substitutions)
|
||||
TiptapService.new.to_path(content_for.deep_symbolize_keys, substitutions)
|
||||
end
|
||||
|
||||
def specific_tags
|
||||
|
|
|
@ -50,9 +50,9 @@ class Procedure < ApplicationRecord
|
|||
has_one :module_api_carto, dependent: :destroy
|
||||
has_many :attestation_templates, dependent: :destroy
|
||||
has_one :attestation_template_v1, -> { AttestationTemplate.v1 }, dependent: :destroy, class_name: "AttestationTemplate", inverse_of: :procedure
|
||||
has_one :attestation_template_v2, -> { AttestationTemplate.v2 }, dependent: :destroy, class_name: "AttestationTemplate", inverse_of: :procedure
|
||||
has_many :attestation_templates_v2, -> { AttestationTemplate.v2 }, dependent: :destroy, class_name: "AttestationTemplate", inverse_of: :procedure
|
||||
|
||||
has_one :attestation_template, -> { order(Arel.sql("CASE WHEN version = '1' THEN 0 ELSE 1 END")) }, dependent: :destroy, inverse_of: :procedure
|
||||
has_one :attestation_template, -> { published }, dependent: :destroy, inverse_of: :procedure
|
||||
|
||||
belongs_to :parent_procedure, class_name: 'Procedure', optional: true
|
||||
belongs_to :canonical_procedure, class_name: 'Procedure', optional: true
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
class TiptapService
|
||||
def to_html(node, substitutions = {})
|
||||
return '' if node.nil?
|
||||
|
||||
children(node[:content], substitutions, 0)
|
||||
end
|
||||
|
||||
def to_path(node, substitutions = {})
|
||||
return '' if node.nil?
|
||||
|
||||
children_path(node[:content], substitutions)
|
||||
end
|
||||
|
||||
# NOTE: node must be deep symbolized keys
|
||||
def used_tags_and_libelle_for(node, tags = Set.new)
|
||||
def self.used_tags_and_libelle_for(node, tags = Set.new)
|
||||
case node
|
||||
in type: 'mention', attrs: { id:, label: }, **rest
|
||||
tags << [id, label]
|
||||
|
@ -25,6 +13,18 @@ class TiptapService
|
|||
tags
|
||||
end
|
||||
|
||||
def to_html(node, substitutions = {})
|
||||
return '' if node.nil?
|
||||
|
||||
children(node[:content], substitutions, 0)
|
||||
end
|
||||
|
||||
def to_path(node, substitutions = {})
|
||||
return '' if node.nil?
|
||||
|
||||
children_path(node[:content], substitutions)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def initialize
|
||||
|
|
23
app/services/weasyprint_service.rb
Normal file
23
app/services/weasyprint_service.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class WeasyprintService
|
||||
def self.generate_pdf(html, options = {})
|
||||
headers = {
|
||||
'Content-Type' => 'application/json',
|
||||
'X-Request-Id' => Current.request_id
|
||||
}
|
||||
|
||||
body = {
|
||||
html:,
|
||||
upstream_context: options
|
||||
}.to_json
|
||||
|
||||
response = Typhoeus.post(WEASYPRINT_URL, headers:, body:)
|
||||
|
||||
if response.success?
|
||||
response.body
|
||||
else
|
||||
raise StandardError, "PDF Generation failed: #{response.code} #{response.status_message}"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
- success = local_assigns.fetch(:success, true)
|
||||
#autosave-notice.fr-badge.fr-badge--sm{ class: class_names("fr-badge--success" => success, "fr-badge--error" => !success) }= success ? t(".form_saved") : t(".form_error")
|
|
@ -0,0 +1,9 @@
|
|||
.fr-container
|
||||
.fr-grid-row.fr-grid-row--middle.fr-pb-3v
|
||||
.fr-col-12.fr-col-md-4
|
||||
= link_to admin_procedure_path(id: procedure), class: 'fr-link' do
|
||||
%span.fr-icon-arrow-left-line.fr-icon--sm
|
||||
Revenir à l’écran de gestion
|
||||
|
||||
.fr-col-12.fr-col-md-8.text-right
|
||||
%span#autosave-notice
|
|
@ -0,0 +1,21 @@
|
|||
.sticky-header.sticky-header-warning
|
||||
.fr-container
|
||||
%p.flex.justify-between.align-center.fr-text-default--warning
|
||||
%span
|
||||
= dsfr_icon("fr-icon-warning-fill fr-mr-1v")
|
||||
- if @procedure.attestation_templates.many?
|
||||
Les modifications effectuées ne seront appliquées qu’à la prochaine publication.
|
||||
- else
|
||||
L’attestation ne sera délivrée qu’après sa publication.
|
||||
|
||||
%span.no-wrap
|
||||
- if @procedure.attestation_templates.many?
|
||||
= link_to reset_admin_procedure_attestation_template_v2_path(@procedure), class: "fr-btn fr-btn--secondary fr-ml-2w", method: :post do
|
||||
Réinitialiser les modifications
|
||||
|
||||
%button.fr-btn.fr-ml-2w{ form: "attestation-template", name: field_name(:attestation_template, :state), value: "published",
|
||||
data: { 'disable-with': "Publication en cours…", controller: 'autosave-submit' } }
|
||||
- if @procedure.attestation_templates.many?
|
||||
Publier les modifications
|
||||
- else
|
||||
Publier
|
|
@ -4,7 +4,8 @@
|
|||
['Attestation']] }
|
||||
|
||||
= render NestedForms::FormOwnerComponent.new
|
||||
= form_for @attestation_template, url: admin_procedure_attestation_template_v2_path(@procedure), html: { multipart: true },
|
||||
= form_for @attestation_template, url: admin_procedure_attestation_template_v2_path(@procedure),
|
||||
html: { multipart: true , id: "attestation-template" },
|
||||
data: { turbo: 'true',
|
||||
controller: 'autosubmit attestation',
|
||||
autosubmit_debounce_delay_value: 1000,
|
||||
|
@ -19,11 +20,12 @@
|
|||
tout en respectant la charte de l’état. Essayez-la et donnez-nous votre avis
|
||||
en nous envoyant un email à #{mail_to(Current.contact_email, subject: "Feedback attestation v2")}.
|
||||
%br
|
||||
%strong Les attestations délivrées suivent encore l’ancien format :
|
||||
l’activation des attestations basées sur ce format sera bientôt disponible.
|
||||
%br
|
||||
- if !@procedure.feature_enabled?(:attestation_v2)
|
||||
%strong Les attestations délivrées suivent encore l’ancien format :
|
||||
l’activation des attestations basées sur ce format sera bientôt disponible.
|
||||
%br
|
||||
|
||||
= link_to("Suivez ce lien pour revenir aux attestations actuellement délivrées", edit_admin_procedure_attestation_template_path(@procedure))
|
||||
= link_to("Suivez ce lien pour revenir aux attestations actuellement délivrées", edit_admin_procedure_attestation_template_path(@procedure))
|
||||
|
||||
.fr-grid-row.fr-grid-row--gutters
|
||||
.fr-col-12.fr-col-lg-7
|
||||
|
@ -34,13 +36,23 @@
|
|||
L’attestation est émise au moment où un dossier est accepté, elle est jointe à l’email d’accusé d’acceptation.
|
||||
Elle est également disponible au téléchargement depuis l’espace personnel de l’usager.
|
||||
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::CalloutComponent.new(title: "Activation de la délivrance de l’attestation", theme: :neutral) do |c|
|
||||
- c.with_html_body do
|
||||
.fr-toggle.fr-toggle--label-left
|
||||
= f.check_box :activated, class: "fr-toggle__input", id: dom_id(@attestation_template, :activated)
|
||||
%label.fr-toggle__label{ for: dom_id(@attestation_template, :activated),
|
||||
data: { fr_checked_label: "Activée", fr_unchecked_label: "Désactivée" } }
|
||||
Activer cette option permet la délivrance automatique de l’attestation dès l’acceptation du dossier.
|
||||
Désactiver cette option arrête immédiatement l’émission de nouvelles attestations.
|
||||
|
||||
.fr-fieldset__element
|
||||
%h2.fr-h4 En-tête
|
||||
|
||||
.fr-fieldset__element
|
||||
.fr-toggle.fr-toggle--label-left
|
||||
= f.check_box :official_layout, class: "fr-toggle__input", id: dom_id(@attestation_template, :official_layout), data: { "attestation-target": "layoutToggle"}
|
||||
%label.fr-toggle__label{ for: dom_id(@attestation_template, :official_layout), data: { fr_checked_label: "Activé", fr_unchecked_label: "Désactivé" } }
|
||||
%label.fr-toggle__label{ for: dom_id(@attestation_template, :official_layout), data: { fr_checked_label: "Oui", fr_unchecked_label: "Non" } }
|
||||
Je souhaite générer une attestation à la charte de l’état (logo avec Marianne)
|
||||
|
||||
.fr-fieldset__element{ class: class_names("hidden" => !@attestation_template.official_layout?), data: { "attestation-target": 'logoMarianneLabelFieldset'} }
|
||||
|
@ -77,10 +89,10 @@
|
|||
%button.fr-btn.fr-btn--secondary.fr-btn--sm{ type: 'button', title: label, class: icon == :hidden ? "hidden" : "fr-icon-#{icon}", data: { action: 'click->tiptap#menuButton', tiptap_target: 'button', tiptap_action: action } }
|
||||
= label
|
||||
|
||||
#editor.tiptap-editor{ data: { tiptap_target: 'editor' }, aria: { describedby: dom_id(f.object, "json-body-messages")} }
|
||||
#editor.tiptap-editor{ data: { tiptap_target: 'editor' }, aria: { describedby: "attestation-template-json-body-messages"} }
|
||||
= f.hidden_field :tiptap_body, data: { tiptap_target: 'input' }
|
||||
|
||||
.fr-error-text{ id: dom_id(f.object, "json-body-messages"), class: class_names("hidden" => !f.object.errors.include?(:json_body)) }
|
||||
.fr-error-text{ id: "attestation-template-json-body-messages", class: class_names("hidden" => !f.object.errors.include?(:json_body)) }
|
||||
- if f.object.errors.include?(:json_body)
|
||||
= render partial: "shared/errors_list", locals: { object: f.object, attribute: :json_body }
|
||||
|
||||
|
@ -108,7 +120,7 @@
|
|||
- c.with_hint { "Exemple: 20 avenue de Ségur, 75007 Paris" }
|
||||
|
||||
#preview-column.fr-col-12.fr-col-lg-5.fr-background-alt--blue-france
|
||||
.sticky--top.fr-px-1w
|
||||
.sticky--top.fr-px-1w{ data: { controller: "sticky-top" } }
|
||||
.flex.justify-between.align-center
|
||||
%h2.fr-h4 Aperçu
|
||||
%p= link_to 'Prévisualiser en taille réelle', admin_procedure_attestation_template_v2_path(@procedure, format: :pdf), class: 'fr-link', target: '_blank', rel: 'noopener'
|
||||
|
@ -117,21 +129,10 @@
|
|||
L’aperçu est mis à jour automatiquement après chaque modification.
|
||||
Pour générer un aperçu fidèle avec tous les champs et les dates, créez-vous un dossier et acceptez-le : l’aperçu l’utilisera.
|
||||
|
||||
.padded-fixed-footer
|
||||
.fixed-footer
|
||||
.fr-container
|
||||
.fr-grid-row
|
||||
.fr-col-12.fr-col-md-7
|
||||
%ul.fr-btns-group.fr-btns-group--inline-md
|
||||
%li
|
||||
= link_to admin_procedure_path(id: @procedure), class: 'fr-btn fr-btn--secondary' do
|
||||
%span.fr-icon-arrow-go-back-line.fr-icon--sm.fr-mr-1v
|
||||
Revenir à la démarche
|
||||
- if @procedure.feature_enabled?(:attestation_v2) && @attestation_template.draft?
|
||||
- content_for(:sticky_header) do
|
||||
= render partial: "sticky_header"
|
||||
|
||||
.fr-col-12.fr-col-md-5
|
||||
-# .fr-toggle
|
||||
-# = f.check_box :activated, class: "fr-toggle-input", disabled: true, id: dom_id(@attestation_template, :activated)
|
||||
-# %label.fr-toggle__label{ for: dom_id(@attestation_template, :activated), data: { fr_checked_label: "Attestation activée", fr_unchecked_label: "Attestation désactivée" } }
|
||||
.text-right
|
||||
%span#autosave-notice
|
||||
%p.fr-hint-text L’activation de cette attestation sera bientôt disponible.
|
||||
.padded-fixed-footer
|
||||
.fixed-footer#fixed_footer
|
||||
= render partial: "fixed_footer", locals: { procedure: @procedure }
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
- if @attestation_template.draft?
|
||||
= turbo_stream.update "sticky-header", render(partial: "sticky_header")
|
||||
|
||||
= turbo_stream.show 'autosave-notice'
|
||||
= turbo_stream.replace 'autosave-notice', render(partial: 'administrateurs/autosave_notice', locals: { success: !@attestation_template.changed? })
|
||||
= turbo_stream.replace('autosave-notice', render(AutosaveNoticeComponent.new(success: !@attestation_template.changed?, label_scope: :attestation)))
|
||||
= turbo_stream.hide 'autosave-notice', delay: 15000
|
||||
|
||||
- if @attestation_template.logo_blob&.previously_new_record?
|
||||
|
@ -10,7 +13,7 @@
|
|||
= turbo_stream.update dom_id(@attestation_template, :signature_attachment) do
|
||||
= render(Attachment::EditComponent.new(attached_file: @attestation_template.signature, direct_upload: false))
|
||||
|
||||
- body_id = dom_id(@attestation_template, "json-body-messages")
|
||||
- body_id = "attestation-template-json-body-messages"
|
||||
- if @attestation_template.errors.include?(:json_body)
|
||||
= turbo_stream.update body_id do
|
||||
= render partial: "shared/errors_list", locals: { object: @attestation_template, attribute: :json_body }
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
- unless flash.alert
|
||||
= turbo_stream.show 'autosave-notice'
|
||||
= turbo_stream.replace 'autosave-notice', render(partial: 'administrateurs/autosave_notice')
|
||||
= turbo_stream.replace 'autosave-notice', render(AutosaveNoticeComponent.new(success: true, label_scope: :form))
|
||||
= turbo_stream.hide 'autosave-notice', delay: 30000
|
||||
|
||||
- if @destroyed.present?
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
#beta
|
||||
Env Test
|
||||
|
||||
#sticky-header.sticky-header-container
|
||||
= content_for(:sticky_header)
|
||||
|
||||
= render partial: "layouts/header"
|
||||
%main#contenu{ role: :main }
|
||||
= render partial: "layouts/flash_messages"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue