Merge pull request #11066 from demarches-simplifiees/add-export-template-page

ETQ Instructeur, je souhaite avoir une page spécifique aux modèles d'exports
This commit is contained in:
Kara Diaby 2024-11-22 13:55:02 +00:00 committed by GitHub
commit d33c594f91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 126 additions and 79 deletions

View file

@ -15,7 +15,7 @@ module Instructeurs
@export_template = ExportTemplate.new(export_template_params)
if @export_template.save
redirect_to [:exports, :instructeur, @procedure], notice: "Le modèle d'export #{@export_template.name} a bien été créé"
redirect_to [:export_templates, :instructeur, @procedure], notice: "Le modèle d'export #{@export_template.name} a bien été créé"
else
flash[:alert] = @export_template.errors.full_messages
render :new

View file

@ -204,7 +204,6 @@ module Instructeurs
def exports
@procedure = procedure
@exports = Export.for_groupe_instructeurs(groupe_instructeur_ids).ante_chronological
@export_templates = current_instructeur.export_templates_for(@procedure).includes(:groupe_instructeur)
cookies.encrypted[cookies_export_key] = {
value: DateTime.current,
expires: Export::MAX_DUREE_GENERATION + Export::MAX_DUREE_CONSERVATION_EXPORT,
@ -218,6 +217,11 @@ module Instructeurs
end
end
def export_templates
@procedure = procedure
@export_templates = current_instructeur.export_templates_for(@procedure).includes(:groupe_instructeur)
end
def email_usagers
@procedure = procedure
@bulk_messages = BulkMessage.where(procedure: procedure)

View file

@ -27,7 +27,9 @@ module NavigationHelper
end
def downloads_section?
params[:action] == 'exports' ||
params[:controller] == 'instructeurs/archives'
return true if params[:action].in?(['exports', 'export_templates'])
return true if params[:controller] == 'instructeurs/archives'
false
end
end

View file

@ -52,7 +52,7 @@
%li
= link_to t('instructeurs.dossiers.header.banner.archives'), instructeur_archives_path(procedure), class: 'fr-nav__link'
%li
= link_to t('instructeurs.dossiers.header.banner.exports_models'), exports_instructeur_procedure_path(procedure), class: 'fr-nav__link'
= link_to t('instructeurs.dossiers.header.banner.export_templates'), export_templates_instructeur_procedure_path(procedure), class: 'fr-nav__link'
- if @has_export_notification
%span.notifications{ 'aria-label': t('instructeurs.dossiers.header.banner.exports_notification_label') }

View file

@ -0,0 +1,49 @@
- title = t('.page_title', procedure: @procedure.libelle)
- content_for(:title, title)
.sub-header
.fr-container.flex.column
= render partial: 'instructeurs/breadcrumbs', locals: { steps: [[@procedure.libelle.truncate_words(10), instructeur_procedure_path(@procedure)], [t('instructeurs.dossiers.header.banner.export_templates')]] }
= render partial: 'instructeurs/procedures/header', locals: { procedure: @procedure }
.fr-container
%h1.fr-h4= t('instructeurs.dossiers.header.banner.export_templates')
= render Dsfr::AlertComponent.new(state: :info) do |c|
- c.with_body do
%p= t('.export_template_list_description_html')
.fr-mt-5w
= link_to t('.new_zip_export_template'), new_instructeur_procedure_export_template_path(@procedure, kind: 'zip'), class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-add-line fr-mr-1w"
= link_to t('.new_tabular_export_template'), new_instructeur_procedure_export_template_path(@procedure, kind: 'tabular'), class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-add-line"
- if @export_templates.any?
.fr-table.fr-table--bordered.fr-table--no-caption.fr-mt-5w
.fr-table__wrapper
.fr-table__container
%table.fr-table__content
%thead
%tr
%th{ scope: 'col' }= t('.template_name')
%th{ scope: 'col' }= t('.template_format')
%th{ scope: 'col' }= t('.template_creation_date')
- if @procedure.groupe_instructeurs.many?
%th{ scope: 'col' }= t('.template_shared_with')
%th{ scope: 'col' }= t('.actions')
%tbody
- @export_templates.each do |export_template|
%tr
%td= link_to export_template.name, [:edit, :instructeur, @procedure, export_template]
%td= pretty_kind(export_template.kind)
%td= l(export_template.created_at)
- if @procedure.groupe_instructeurs.many?
%td= export_template.groupe_instructeur.label
%td
= link_to t('.modify_template'), [:edit, :instructeur, @procedure, export_template], class: "fr-btn fr-btn--icon-left fr-icon-edit-line fr-mr-1w"
= link_to t('.delete_template'), [:instructeur, @procedure, export_template], method: :delete, data: { confirm: t('.delete_template_alert')}, class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-delete-line"
- else
.fr-alert.fr-alert--info.fr-mt-4w
.fr-alert__body
%p= t('.no_existing_template')

View file

@ -12,59 +12,19 @@
.fr-container
%h1.fr-h4= t('.title')
.fr-tabs.mb-3
%ul.fr-tabs__list{ role: 'tablist' }
%li{ role: 'presentation' }
%button.fr-tabs__tab.fr-tabs__tab--icon-left{ id: "tabpanel-exports", tabindex: "0", role: "tab", "aria-selected": "true", "aria-controls": "tabpanel-exports-panel" } Liste des exports
%li{ role: 'presentation' }
%button.fr-tabs__tab.fr-tabs__tab--icon-left{ id: "tabpanel-export-templates", tabindex: "-1", role: "tab", "aria-selected": "false", "aria-controls": "tabpanel-export-templates-panel" } Modèles d'export
.fr-tabs__panel.fr-tabs__panel--selected{ id: "tabpanel-exports-panel", role: "tabpanel", "aria-labelledby": "tabpanel-exports", tabindex: "0" }
= render Dsfr::CalloutComponent.new(title: nil) do |c|
= render Dsfr::CalloutComponent.new(title: nil) do |c|
- c.with_body do
%p= t('.export_description', expiration_time: Export::MAX_DUREE_CONSERVATION_EXPORT.in_hours.to_i)
- if @exports.present?
%div{ data: @exports.any?(&:pending?) ? { controller: "turbo-poll", turbo_poll_url_value: "", turbo_poll_interval_value: 10_000, turbo_poll_max_checks_value: 6 } : {} }
= render Dossiers::ExportLinkComponent.new(procedure: @procedure, exports: @exports, statut: @statut, count: @dossiers_count, class_btn: 'fr-btn--tertiary', export_url: method(:download_export_instructeur_procedure_path))
- if @exports.any?{_1.format == Export.formats.fetch(:zip)}
= render Dsfr::AlertComponent.new(title: t('.title_zip'), state: :info, extra_class_names: 'fr-mb-3w') do |c|
- c.with_body do
%p= t('.export_description', expiration_time: Export::MAX_DUREE_CONSERVATION_EXPORT.in_hours.to_i)
%p= t('.export_description_zip_html')
- if @exports.present?
%div{ data: @exports.any?(&:pending?) ? { controller: "turbo-poll", turbo_poll_url_value: "", turbo_poll_interval_value: 10_000, turbo_poll_max_checks_value: 6 } : {} }
= render Dossiers::ExportLinkComponent.new(procedure: @procedure, exports: @exports, statut: @statut, count: @dossiers_count, class_btn: 'fr-btn--tertiary', export_url: method(:download_export_instructeur_procedure_path))
- if @exports.any?{_1.format == Export.formats.fetch(:zip)}
= render Dsfr::AlertComponent.new(title: t('.title_zip'), state: :info, extra_class_names: 'fr-mb-3w') do |c|
- c.with_body do
%p= t('.export_description_zip_html')
- else
= t('.no_export_html', expiration_time: Export::MAX_DUREE_CONSERVATION_EXPORT.in_hours.to_i )
.fr-tabs__panel.fr-tabs__panel{ id: "tabpanel-export-templates-panel", role: "tabpanel", "aria-labelledby": "tabpanel-export-templates", tabindex: "0" }
= render Dsfr::AlertComponent.new(state: :info) do |c|
- c.with_body do
%p= t('.export_template_list_description_html')
.fr-mt-5w
= link_to t('.new_zip_export_template'), new_instructeur_procedure_export_template_path(@procedure, kind: 'zip'), class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-add-line fr-mr-1w"
= link_to t('.new_tabular_export_template'), new_instructeur_procedure_export_template_path(@procedure, kind: 'tabular'), class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-add-line"
.fr-table.fr-table--bordered.fr-table--no-caption.fr-mt-5w
.fr-table__wrapper
.fr-table__container
.fr-table__content
%table
%thead
%tr
= tag.th "Nom du modèle", scope: 'col'
= tag.th "Format", scope: 'col'
= tag.th "Date de création", scope: 'col'
= tag.th "Partagé avec (groupe instructeurs)", scope: 'col' if @procedure.groupe_instructeurs.many?
= tag.th "Actions", scope: 'col'
%tbody
- @export_templates.each do |export_template|
%tr
%td= link_to export_template.name, [:edit, :instructeur, @procedure, export_template]
%td= pretty_kind(export_template.kind)
%td= l(export_template.created_at)
= tag.td export_template.groupe_instructeur.label if @procedure.groupe_instructeurs.many?
%td
= link_to "Modifier", [:edit, :instructeur, @procedure, export_template], class: "fr-btn fr-btn--icon-left fr-icon-edit-line fr-mr-1w"
= link_to "Supprimer", [:instructeur, @procedure, export_template], method: :delete, data: { confirm: "Voulez-vous vraiment supprimer ce modèle ? Il sera supprimé pour tous les instructeurs du groupe"}, class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-delete-line"
- else
= t('.no_export_html', expiration_time: Export::MAX_DUREE_CONSERVATION_EXPORT.in_hours.to_i )

View file

@ -15,6 +15,7 @@ en:
notification_management: notification management
administrators_list: administrators list
exports_list: exports and export templates
export_templates: Export templates
exports_notification_label: A new export is ready to download
statistics: statistics
instructeurs: instructors

View file

@ -16,7 +16,7 @@ fr:
procedure_management: Gestion de la démarche
administrators_list: Administrateurs de la démarche
exports_list: Liste des exports
exports_models: Modèles d'exports
export_templates: Modèles d'export
exports_notification_label: Un nouvel export est prêt à être téléchargé
statistics: Statistiques de la démarche
user_support: Accompagnement des usagers

View file

@ -18,9 +18,19 @@ en:
no_export_html: You have no export at the moment. <br> Can't find an export? It may have expired, exports are deleted after %{expiration_time} hours.
export_templates:
export_template_list_description_html: |
Each instructor can <b>configure an export template</b> to customize exports (attachments name for a zip export, columns selection for a tabular export). It will be made <b>available to all instructors</b> assigned to the procedure.</br>
<a href="https://doc.demarches-simplifiees.fr" target="_blank" rel="noopener noreferrer">Find out more about export template configuration</a>
new_zip_export_template: Create zip export template
new_zip_export_template: Create ZIP export template
new_tabular_export_template: Create tabular export template
template_name: Template name
no_existing_template: No export templates have been created yet. Use the buttons above to get started.
template_format: Format
template_creation_date: Creation date
template_shared_with: Shared with (instructor groups)
modify_template: Edit
delete_template: Delete
delete_template_alert: Are you sure you want to delete this template? It will be removed for all instructors in the group
page_title: "Export templates · %{procedure}"
actions: Actions

View file

@ -17,8 +17,19 @@ fr:
Vous n'arrivez pas à extraire un export au format .zip sur un réseau d'entreprise ? Essayer de renommer l'archive avec un nom plus court et ré-essayer de l'extraire.
no_export_html: Vous n'avez pas d'export pour le moment. <br> Vous ne trouvez pas un export ? Il a peut-être expiré, les exports sont supprimés au bout de %{expiration_time} heures.
export_templates:
export_template_list_description_html: |
Chaque instructeur a la possibilité de <b>configurer un modèle</b> d'export pour personnaliser les exports (nom des pièces jointes pour un export au format zip, sélection des colonnes pour un export tabulaire). Il sera <b>mis à disposition de l'ensemble des instructeurs</b> affectés à la démarche<br>
<a href="https://doc.demarches-simplifiees.fr" target="_blank" rel="noopener noreferrer">En savoir plus sur la configuration des modèles d'export</a>
new_zip_export_template: Créer un modèle d'export zip
new_tabular_export_template: Créer un modèle d'export tabulaire
template_name: Nom du modèle
no_existing_template: Aucun modèle d'export n'a encore été créé. Utilisez les boutons ci-dessus pour commencer.
template_format: Format
template_creation_date: Date de création
template_shared_with: Partagé avec (groupe instructeurs)
modify_template: Modifier
delete_template: Supprimer
delete_template_alert: Voulez-vous vraiment supprimer ce modèle ? Il sera supprimé pour tous les instructeurs du groupe
page_title: "Modèles d'export · %{procedure}"
actions: Actions

View file

@ -495,6 +495,7 @@ Rails.application.routes.draw do
get 'polling_last_export'
get 'stats'
get 'exports'
get 'export_templates'
get 'email_notifications'
get 'administrateurs'
patch 'update_email_notifications'

View file

@ -42,7 +42,7 @@ describe Instructeurs::ExportTemplatesController, type: :controller do
context 'with valid params' do
it 'redirect to some page' do
subject
expect(response).to redirect_to(exports_instructeur_procedure_path(procedure))
expect(response).to redirect_to(export_templates_instructeur_procedure_path(procedure))
expect(flash.notice).to eq "Le modèle d'export coucou a bien été créé"
end
end
@ -116,7 +116,7 @@ describe Instructeurs::ExportTemplatesController, type: :controller do
context 'with valid params' do
it 'redirect to some page' do
subject
expect(response).to redirect_to(exports_instructeur_procedure_path(procedure))
expect(response).to redirect_to(export_templates_instructeur_procedure_path(procedure))
expect(flash.notice).to eq "Le modèle d'export ExportODS a bien été créé"
expect(ExportTemplate.last.exported_columns.map(&:libelle)).to match_array ['Demandeur', 'Date du dernier évènement']
end

View file

@ -869,6 +869,27 @@ describe Instructeurs::ProceduresController, type: :controller do
end
end
describe '#export_templates' do
render_views
let(:instructeur) { create(:instructeur) }
let(:procedure) { create(:procedure) }
let(:groupe_instructeur) { create(:groupe_instructeur, procedure: procedure) }
let!(:export_template) { create(:export_template, name: "My Template", groupe_instructeur: groupe_instructeur) }
before do
sign_in(instructeur.user)
create(:assign_to, instructeur: instructeur, groupe_instructeur: groupe_instructeur)
end
it 'displays export templates' do
get :export_templates, params: { procedure_id: procedure.id }
expect(response).to have_http_status(:success)
expect(response.body).to include("My Template")
end
end
describe '#exports' do
let(:instructeur) { create(:instructeur) }
let!(:procedure) { create(:procedure) }

View file

@ -12,8 +12,6 @@ describe "procedure exports" do
find("button", text: "Téléchargements").click
click_on "Liste des exports"
click_on "Modèles d'export"
click_on "Créer un modèle d'export tabulaire"
@ -21,23 +19,20 @@ describe "procedure exports" do
fill_in "Nom du modèle", with: "Mon modèle"
find("#informations-usager-fieldset label", text: "Tout sélectionner").click
within '#informations-usager-fieldset' do
expect(all('input[type=checkbox]').all?(&:checked?)).to be_truthy
end
find("#informations-dossier-fieldset label", text: "Tout sélectionner").click
within '#informations-dossier-fieldset' do
expect(all('input[type=checkbox]').all?(&:checked?)).to be_truthy
end
click_on "Enregistrer"
find("#tabpanel-export-templates", wait: 5, visible: true)
find("#tabpanel-export-templates").click
within 'table' do
expect(page).to have_content('Mon modèle')
end
expect(page).to have_content('Mon modèle')
# check if all usager colonnes are selected
#

View file

@ -11,8 +11,6 @@ describe "procedure exports zip" do
find("button", text: "Téléchargements").click
click_on "Liste des exports"
click_on "Modèles d'export"
click_on "Créer un modèle d'export zip"
@ -21,11 +19,6 @@ describe "procedure exports zip" do
expect(page).to have_content("Sélectionnez les fichiers que vous souhaitez exporter")
click_on "Enregistrer"
find("#tabpanel-export-templates", wait: 5, visible: true)
find("#tabpanel-export-templates").click
within 'table' do
expect(page).to have_content('Mon modèle')
end
expect(page).to have_content('Mon modèle')
end
end