diff --git a/app/controllers/instructeurs/export_templates_controller.rb b/app/controllers/instructeurs/export_templates_controller.rb index 453673b42..f78e3550c 100644 --- a/app/controllers/instructeurs/export_templates_controller.rb +++ b/app/controllers/instructeurs/export_templates_controller.rb @@ -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 diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index e7772b88e..a93eabf2f 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -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) diff --git a/app/helpers/navigation_helper.rb b/app/helpers/navigation_helper.rb index 870785327..662ffac1d 100644 --- a/app/helpers/navigation_helper.rb +++ b/app/helpers/navigation_helper.rb @@ -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 diff --git a/app/views/instructeurs/procedures/_header.html.haml b/app/views/instructeurs/procedures/_header.html.haml index c990fade0..f144f9abd 100644 --- a/app/views/instructeurs/procedures/_header.html.haml +++ b/app/views/instructeurs/procedures/_header.html.haml @@ -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') } diff --git a/app/views/instructeurs/procedures/export_templates.html.haml b/app/views/instructeurs/procedures/export_templates.html.haml new file mode 100644 index 000000000..1cb76e076 --- /dev/null +++ b/app/views/instructeurs/procedures/export_templates.html.haml @@ -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') diff --git a/app/views/instructeurs/procedures/exports.html.haml b/app/views/instructeurs/procedures/exports.html.haml index f22aecc25..30021b77e 100644 --- a/app/views/instructeurs/procedures/exports.html.haml +++ b/app/views/instructeurs/procedures/exports.html.haml @@ -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 ) diff --git a/config/locales/views/instructeurs/header/en.yml b/config/locales/views/instructeurs/header/en.yml index 3e4299acb..39c7ca7c7 100644 --- a/config/locales/views/instructeurs/header/en.yml +++ b/config/locales/views/instructeurs/header/en.yml @@ -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 diff --git a/config/locales/views/instructeurs/header/fr.yml b/config/locales/views/instructeurs/header/fr.yml index d3b7e4fbe..c96de8e14 100644 --- a/config/locales/views/instructeurs/header/fr.yml +++ b/config/locales/views/instructeurs/header/fr.yml @@ -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 diff --git a/config/locales/views/instructeurs/procedures/exports/en.yml b/config/locales/views/instructeurs/procedures/exports/en.yml index f1f7bc753..762bc8cc9 100644 --- a/config/locales/views/instructeurs/procedures/exports/en.yml +++ b/config/locales/views/instructeurs/procedures/exports/en.yml @@ -18,9 +18,19 @@ en: no_export_html: You have no export at the moment.
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 configure an export template to customize exports (attachments name for a zip export, columns selection for a tabular export). It will be made available to all instructors assigned to the procedure.
Find out more about export template configuration - 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 diff --git a/config/locales/views/instructeurs/procedures/exports/fr.yml b/config/locales/views/instructeurs/procedures/exports/fr.yml index fa0945652..40760b6e3 100644 --- a/config/locales/views/instructeurs/procedures/exports/fr.yml +++ b/config/locales/views/instructeurs/procedures/exports/fr.yml @@ -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.
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 configurer un modèle 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 mis à disposition de l'ensemble des instructeurs affectés à la démarche
En savoir plus sur la configuration des modèles d'export 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 diff --git a/config/routes.rb b/config/routes.rb index 518f513aa..f4532277e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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' diff --git a/spec/controllers/instructeurs/export_templates_controller_spec.rb b/spec/controllers/instructeurs/export_templates_controller_spec.rb index 32fba6ba8..573d514b2 100644 --- a/spec/controllers/instructeurs/export_templates_controller_spec.rb +++ b/spec/controllers/instructeurs/export_templates_controller_spec.rb @@ -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 diff --git a/spec/controllers/instructeurs/procedures_controller_spec.rb b/spec/controllers/instructeurs/procedures_controller_spec.rb index d759412f9..bb9725a39 100644 --- a/spec/controllers/instructeurs/procedures_controller_spec.rb +++ b/spec/controllers/instructeurs/procedures_controller_spec.rb @@ -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) } diff --git a/spec/system/instructeurs/procedure_export_template_tabular_spec.rb b/spec/system/instructeurs/procedure_export_template_tabular_spec.rb index bdefa98f6..056887be2 100644 --- a/spec/system/instructeurs/procedure_export_template_tabular_spec.rb +++ b/spec/system/instructeurs/procedure_export_template_tabular_spec.rb @@ -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 # diff --git a/spec/system/instructeurs/procedure_export_template_zip_spec.rb b/spec/system/instructeurs/procedure_export_template_zip_spec.rb index 90e376751..8aeee3454 100644 --- a/spec/system/instructeurs/procedure_export_template_zip_spec.rb +++ b/spec/system/instructeurs/procedure_export_template_zip_spec.rb @@ -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