diff --git a/app/assets/stylesheets/forms.scss b/app/assets/stylesheets/forms.scss index ce83a13bb..6073283bc 100644 --- a/app/assets/stylesheets/forms.scss +++ b/app/assets/stylesheets/forms.scss @@ -551,3 +551,22 @@ textarea::placeholder { .resize-y { resize: vertical; } + +.checkbox-group-bordered { + border: 1px solid var(--border-default-grey); + flex: 1 1 100%; // copied from fr-fieldset-element + max-width: 100%; // copied from fr-fieldset-element +} + +.fieldset-bordered { + position: relative; +} + +.fieldset-bordered::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + border-left: 2px solid var(--border-default-blue-france); +} diff --git a/app/components/export_template/champs_component.rb b/app/components/export_template/champs_component.rb new file mode 100644 index 000000000..e12b2d5d9 --- /dev/null +++ b/app/components/export_template/champs_component.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class ExportTemplate::ChampsComponent < ApplicationComponent + attr_reader :export_template, :title + + def initialize(title, export_template, types_de_champ) + @title = title + @export_template = export_template + @types_de_champ = types_de_champ + end + + def historical_libelle(column) + historical_exported_column = export_template.exported_columns.find { _1.column == column } + if historical_exported_column + historical_exported_column.libelle + else + column.label + end + end + + def sections + @types_de_champ + .reject { _1.header_section? && _1.header_section_level_value > 1 } + .slice_before(&:header_section?) + .filter_map do |(head, *rest)| + libelle = head.libelle if head.header_section? + columns = [head.header_section? ? nil : head, *rest].compact.map { tdc_to_columns(_1) } + { libelle:, columns: } if columns.present? + end + end + + def component_prefix + title.parameterize + end + + private + + def tdc_to_columns(type_de_champ) + prefix = type_de_champ.repetition? ? "Bloc répétable" : nil + type_de_champ.columns(procedure: export_template.procedure, prefix:).map do |column| + ExportedColumn.new(column:, + libelle: historical_libelle(column)) + end + end +end diff --git a/app/components/export_template/champs_component/champs_component.html.haml b/app/components/export_template/champs_component/champs_component.html.haml new file mode 100644 index 000000000..4ccbe41de --- /dev/null +++ b/app/components/export_template/champs_component/champs_component.html.haml @@ -0,0 +1,29 @@ +%fieldset.fr-fieldset{ id: "#{component_prefix}-fieldset", data: { controller: 'checkbox-select-all' } } + %legend.fr-fieldset__legend--regular.fr-fieldset__legend + = title + .checkbox-group-bordered.fr-mx-1w.fr-mb-2w + .fr-fieldset__element.fr-background-contrast--grey.fr-py-2w.fr-px-4w + .fr-checkbox-group + = check_box_tag "#{component_prefix}-select-all", "select-all", false, data: { "checkbox-select-all-target": 'checkboxAll' } + = label_tag "#{component_prefix}-select-all", "Tout sélectionner" + - sections.each.with_index do |section, idx| + - if section[:libelle] + .fr-fieldset__element.fr-text--bold.fr-px-4w{ class: idx > 0 ? "fr-pt-1w" : "" }= section[:libelle] + + - section[:columns].each do |grouped_columns| + - if grouped_columns.many? + .fr-fieldset__element + .fieldset-bordered.fr-ml-3v + - grouped_columns.each do |exported_column| + .fr-fieldset__element.fr-px-3v + .fr-checkbox-group + - id = sanitize_to_id(field_id('export_template', 'exported_columns', exported_column.id)) + = check_box_tag field_name('export_template', 'exported_columns', ''), exported_column.id, export_template.exported_columns.map(&:column).include?(exported_column.column), class: 'fr-checkbox', id: id, data: { "checkbox-select-all-target": 'checkbox' } + = label_tag id, historical_libelle(exported_column.column) + - else + - grouped_columns.each do |exported_column| + .fr-fieldset__element.fr-px-4w + .fr-checkbox-group + - id = sanitize_to_id(field_id('export_template', 'exported_columns', exported_column.id)) + = check_box_tag field_name('export_template', 'exported_columns', ''), exported_column.id, export_template.exported_columns.map(&:column).include?(exported_column.column), class: 'fr-checkbox', id: id, data: { "checkbox-select-all-target": 'checkbox' } + = label_tag id, historical_libelle(exported_column.column) diff --git a/app/controllers/instructeurs/export_templates_controller.rb b/app/controllers/instructeurs/export_templates_controller.rb index 49d2e3db8..453673b42 100644 --- a/app/controllers/instructeurs/export_templates_controller.rb +++ b/app/controllers/instructeurs/export_templates_controller.rb @@ -5,9 +5,10 @@ module Instructeurs before_action :set_procedure_and_groupe_instructeurs before_action :set_export_template, only: [:edit, :update, :destroy] before_action :ensure_legitimate_groupe_instructeur, only: [:create, :update] + before_action :set_types_de_champ, only: [:new, :edit] def new - @export_template = ExportTemplate.default(groupe_instructeur: @groupe_instructeurs.first) + @export_template = export_template end def create @@ -49,9 +50,29 @@ module Instructeurs private + def export_template = @export_template ||= ExportTemplate.default(groupe_instructeur: @groupe_instructeurs.first, kind:) + + def kind = params[:kind] == 'zip' ? 'zip' : 'xlsx' + + def set_types_de_champ + if export_template.tabular? + @types_de_champ_public = @procedure.all_revisions_types_de_champ(parent: nil, with_header_section: true).public_only + @types_de_champ_private = @procedure.all_revisions_types_de_champ(parent: nil, with_header_section: true).private_only + end + end + def export_template_params - params.require(:export_template) - .permit(:name, :kind, :groupe_instructeur_id, dossier_folder: [:enabled, :template], export_pdf: [:enabled, :template], pjs: [:stable_id, :enabled, :template]) + params + .require(:export_template) + .permit( + :name, + :kind, + :groupe_instructeur_id, + dossier_folder: [:enabled, :template], + export_pdf: [:enabled, :template], + pjs: [:stable_id, :enabled, :template], + exported_columns: [] + ) end def set_procedure_and_groupe_instructeurs diff --git a/app/helpers/export_template_helper.rb b/app/helpers/export_template_helper.rb new file mode 100644 index 000000000..518de7521 --- /dev/null +++ b/app/helpers/export_template_helper.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module ExportTemplateHelper + def pretty_kind(kind) + icon = kind == 'zip' ? 'archive' : 'table' + pretty = tag.span nil, class: "fr-icon-#{icon}-line fr-mr-1v" + pretty + kind.upcase + end +end diff --git a/app/javascript/controllers/checkbox_select_all_controller.ts b/app/javascript/controllers/checkbox_select_all_controller.ts new file mode 100644 index 000000000..86fbe44d4 --- /dev/null +++ b/app/javascript/controllers/checkbox_select_all_controller.ts @@ -0,0 +1,71 @@ +import { ApplicationController } from './application_controller'; + +export class CheckboxSelectAll extends ApplicationController { + declare readonly hasCheckboxAllTarget: boolean; + declare readonly checkboxTargets: HTMLInputElement[]; + declare readonly checkboxAllTarget: HTMLInputElement; + + static targets: string[] = ['checkboxAll', 'checkbox']; + + initialize() { + this.toggle = this.toggle.bind(this); + this.refresh = this.refresh.bind(this); + } + + checkboxAllTargetConnected(checkbox: HTMLInputElement): void { + checkbox.addEventListener('change', this.toggle); + + this.refresh(); + } + + checkboxTargetConnected(checkbox: HTMLInputElement): void { + checkbox.addEventListener('change', this.refresh); + + this.refresh(); + } + + checkboxAllTargetDisconnected(checkbox: HTMLInputElement): void { + checkbox.removeEventListener('change', this.toggle); + + this.refresh(); + } + + checkboxTargetDisconnected(checkbox: HTMLInputElement): void { + checkbox.removeEventListener('change', this.refresh); + + this.refresh(); + } + + toggle(e: Event): void { + e.preventDefault(); + + this.checkboxTargets.forEach((checkbox) => { + // @ts-expect-error faut savoir hein + checkbox.checked = e.target.checked; + this.triggerInputEvent(checkbox); + }); + } + + refresh(): void { + const checkboxesCount = this.checkboxTargets.length; + const checkboxesCheckedCount = this.checked.length; + + this.checkboxAllTarget.checked = checkboxesCheckedCount > 0; + this.checkboxAllTarget.indeterminate = + checkboxesCheckedCount > 0 && checkboxesCheckedCount < checkboxesCount; + } + + triggerInputEvent(checkbox: HTMLInputElement): void { + const event = new Event('input', { bubbles: false, cancelable: true }); + + checkbox.dispatchEvent(event); + } + + get checked(): HTMLInputElement[] { + return this.checkboxTargets.filter((checkbox) => checkbox.checked); + } + + get unchecked(): HTMLInputElement[] { + return this.checkboxTargets.filter((checkbox) => !checkbox.checked); + } +} diff --git a/app/models/types_de_champ/repetition_type_de_champ.rb b/app/models/types_de_champ/repetition_type_de_champ.rb index 043294933..7470162fd 100644 --- a/app/models/types_de_champ/repetition_type_de_champ.rb +++ b/app/models/types_de_champ/repetition_type_de_champ.rb @@ -26,9 +26,11 @@ class TypesDeChamp::RepetitionTypeDeChamp < TypesDeChamp::TypeDeChampBase end def columns(procedure:, displayable: nil, prefix: nil) + prefix = prefix.present? ? "(#{prefix} #{libelle})" : libelle + procedure .all_revisions_types_de_champ(parent: @type_de_champ) - .flat_map { _1.columns(procedure:, displayable: false, prefix: libelle) } + .flat_map { _1.columns(procedure:, displayable: false, prefix:) } end def champ_blank?(champ) = champ.dossier.repetition_row_ids(@type_de_champ).blank? diff --git a/app/views/administrateurs/archives/index.html.haml b/app/views/administrateurs/archives/index.html.haml index b50059d6c..86cc6465e 100644 --- a/app/views/administrateurs/archives/index.html.haml +++ b/app/views/administrateurs/archives/index.html.haml @@ -4,11 +4,12 @@ ['Export et Archives']] } -.container - %h1.mb-2 +.container.flex + %h1.mb-2.mr-2 Archives -# index not renderable as administrateur flagged as manager, so render it anyway - = render Dossiers::ExportDropdownComponent.new(procedure: @procedure, export_url: method(:download_admin_procedure_exports_path)) + = render Dossiers::ExportDropdownComponent.new(procedure: @procedure, export_url: method(:download_admin_procedure_exports_path), show_export_template_tab: false) +.container = render Dossiers::ExportLinkComponent.new(procedure: @procedure, exports: @exports, export_url: method(:download_admin_procedure_exports_path)) = render partial: "shared/archives/notice" diff --git a/app/views/instructeurs/export_templates/_checkbox_group.html.haml b/app/views/instructeurs/export_templates/_checkbox_group.html.haml new file mode 100644 index 000000000..f6cfd0c23 --- /dev/null +++ b/app/views/instructeurs/export_templates/_checkbox_group.html.haml @@ -0,0 +1,16 @@ +%fieldset.fr-fieldset{ id: "#{title.parameterize}-fieldset", data: { controller: 'checkbox-select-all' } } + %legend.fr-fieldset__legend--regular.fr-fieldset__legend + = title + + .checkbox-group-bordered.fr-mx-1w.fr-mb-2w + .fr-fieldset__element.fr-background-contrast--grey.fr-py-2w.fr-px-4w + .fr-checkbox-group + = check_box_tag "#{title.parameterize}-select-all", "select-all", false, data: { "checkbox-select-all-target": 'checkboxAll' } + = label_tag "#{title.parameterize}-select-all", "Tout sélectionner" + + - all_columns.each do |column| + .fr-fieldset__element.fr-px-4w + .fr-checkbox-group + - id = sanitize_to_id(field_id('export_template', 'exported_columns', { id: column.id, libelle: column.label, parent: nil }.to_json)) + = check_box_tag field_name('export_template', 'exported_columns', ''), { id: column.id, libelle: column.label, parent: nil }.to_json, checked_columns.map(&:column).include?(column), class: 'fr-checkbox', id: id, data: { "checkbox-select-all-target": 'checkbox' } + = label_tag id, column.label diff --git a/app/views/instructeurs/export_templates/_form_tabular.html.haml b/app/views/instructeurs/export_templates/_form_tabular.html.haml new file mode 100644 index 000000000..0da716e9e --- /dev/null +++ b/app/views/instructeurs/export_templates/_form_tabular.html.haml @@ -0,0 +1,57 @@ +#export_template-edit.fr-my-4w + .fr-mb-6w + = render Dsfr::AlertComponent.new(state: :info, title: "Nouvel éditeur de modèle d'export", heading_level: 'h3') do |c| + - c.with_body do + = t('.info_html', mailto: mail_to(CONTACT_EMAIL, subject: 'Editeur de modèle d\'export')) + +.fr-grid-row.fr-grid-row--gutters + .fr-col-12.fr-col-md-8 + = form_with model: [:instructeur, @procedure, export_template], local: true do |f| + + %h2 Paramètres de l'export + = f.hidden_field "[dossier_folder][template]", value: export_template.dossier_folder.template_json + = f.hidden_field "[export_pdf][template]", value: export_template.export_pdf.template_json + + = render Dsfr::InputComponent.new(form: f, attribute: :name, input_type: :text_field) + + - if groupe_instructeurs.many? + .fr-input-group + = f.label :groupe_instructeur_id, class: 'fr-label' do + = f.object.class.human_attribute_name(:groupe_instructeur_id) + = render EditableChamp::AsteriskMandatoryComponent.new + %span.fr-hint-text + Avec quel groupe instructeur souhaitez-vous partager ce modèle d'export ? + = f.collection_select :groupe_instructeur_id, groupe_instructeurs, :id, :label, {}, class: 'fr-select' + - else + = f.hidden_field :groupe_instructeur_id + + %fieldset.fr-fieldset.fr-fieldset--inline + %legend#radio-inline-legend.fr-fieldset__legend.fr-text--regular + Format export + .fr-fieldset__element.fr-fieldset__element--inline + .fr-radio-group + = f.radio_button :kind, "ods", id: "ods" + %label.fr-label{ for: "ods" } ods + .fr-radio-group + = f.radio_button :kind, "xlsx", id: "xlsx" + %label.fr-label{ for: "xlsx" } xlsx + .fr-radio-group + = f.radio_button :kind, "csv", id: "csv" + %label.fr-label{ for: "csv" } csv + + %h2 Contenu de l'export + = render partial: 'checkbox_group', locals: { title: 'Colonnes Usager', all_columns: @export_template.procedure.usager_columns_for_export, checked_columns: @export_template.exported_columns } + = render partial: 'checkbox_group', locals: { title: 'Colonnes Infos dossier', all_columns: @export_template.procedure.dossier_columns_for_export, checked_columns: @export_template.exported_columns } + = render ExportTemplate::ChampsComponent.new("Informations formulaire", @export_template, @types_de_champ_public) + = render ExportTemplate::ChampsComponent.new("Informations annotations", @export_template, @types_de_champ_private) if @types_de_champ_private.any? + + .fixed-footer + .fr-container + %ul.fr-btns-group.fr-btns-group--inline-md + %li + = f.submit "Enregistrer", class: "fr-btn" + %li + = link_to "Annuler", instructeur_procedure_path(@procedure), class: "fr-btn fr-btn--secondary" + - if @export_template.persisted? + %li + = 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" diff --git a/app/views/instructeurs/export_templates/edit.html.haml b/app/views/instructeurs/export_templates/edit.html.haml index ab4c5f8c7..32a80d8d6 100644 --- a/app/views/instructeurs/export_templates/edit.html.haml +++ b/app/views/instructeurs/export_templates/edit.html.haml @@ -4,4 +4,7 @@ .fr-container %h1 Mise à jour modèle d'export - = render partial: 'form', locals: { export_template: @export_template, groupe_instructeurs: @groupe_instructeurs } + - if @export_template.tabular? + = render partial: 'form_tabular', locals: { export_template: @export_template, groupe_instructeurs: @groupe_instructeurs } + - else + = render partial: 'form', locals: { export_template: @export_template, groupe_instructeurs: @groupe_instructeurs } diff --git a/app/views/instructeurs/export_templates/new.html.haml b/app/views/instructeurs/export_templates/new.html.haml index 10962b1cd..358bab190 100644 --- a/app/views/instructeurs/export_templates/new.html.haml +++ b/app/views/instructeurs/export_templates/new.html.haml @@ -3,4 +3,7 @@ [t('.title')]] } .fr-container %h1 Nouveau modèle d'export - = render partial: 'form', locals: { export_template: @export_template, groupe_instructeurs: @groupe_instructeurs } + - if @export_template.tabular? + = render partial: 'form_tabular', locals: { export_template: @export_template, groupe_instructeurs: @groupe_instructeurs } + - else + = render partial: 'form', locals: { export_template: @export_template, groupe_instructeurs: @groupe_instructeurs } diff --git a/config/locales/models/export_templates/en.yml b/config/locales/models/export_templates/en.yml index 1952e0bc0..bcc3ba867 100644 --- a/config/locales/models/export_templates/en.yml +++ b/config/locales/models/export_templates/en.yml @@ -17,3 +17,12 @@ en: dossier_number_required: "must contain dossier's number" different_templates: "Files must have different names" invalid_template: "A file name is invalid" + base: + invalid: "is invalid" + instructeurs: + export_templates: + form_tabular: + info_html: | + This page allows you to edit a tabular export template and select fields that you want to export. + Try it and let us know what you think by sending an e-mail to %{mailto}. + warning: If you modify this template, it will also be modified for all instructors who have access to this template. diff --git a/config/locales/models/export_templates/fr.yml b/config/locales/models/export_templates/fr.yml index 9d152bbc5..f2100fe33 100644 --- a/config/locales/models/export_templates/fr.yml +++ b/config/locales/models/export_templates/fr.yml @@ -17,3 +17,13 @@ fr: dossier_number_required: doit contenir le numéro du dossier different_templates: Les fichiers doivent avoir des noms différents invalid_template: Un nom de fichier est invalide + base: + invalid: "est invalide" + instructeurs: + export_templates: + form_tabular: + info_html: | + Cette page permet d'éditer un modèle d'export tabulaire et ainsi sélectionner les champs que vous souhaitez exporter. + Essayez-le et donnez-nous votre avis + en nous envoyant un email à %{mailto}. + warning: Si vous modifiez ce modèle, il sera également modifié pour tous les instructeurs qui ont accès à ce modèle. diff --git a/spec/components/export_template/champs_component_spec.rb b/spec/components/export_template/champs_component_spec.rb new file mode 100644 index 000000000..23baff354 --- /dev/null +++ b/spec/components/export_template/champs_component_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +describe ExportTemplate::ChampsComponent, type: :component do + let(:groupe_instructeur) { create(:groupe_instructeur, procedure:) } + let(:export_template) { build(:export_template, kind: 'csv', groupe_instructeur:) } + let(:procedure) { create(:procedure_with_dossiers, :published, types_de_champ_public:, for_individual:) } + let(:for_individual) { true } + let(:types_de_champ_public) do + [ + { type: :text, libelle: "Ca va ?", mandatory: true, stable_id: 1 }, + { type: :communes, libelle: "Commune", mandatory: true, stable_id: 17 }, + { type: :siret, libelle: 'Siret', stable_id: 20 }, + { type: :repetition, mandatory: true, stable_id: 7, libelle: "Amis", children: [{ type: 'text', libelle: 'Prénom', stable_id: 8 }] } + ] + end + let(:component) { described_class.new("Champs publics", export_template, procedure.all_revisions_types_de_champ(parent: nil, with_header_section: true)) } + before { render_inline(component).to_html } + + it 'renders champs within fieldset' do + procedure + expect(page).to have_unchecked_field "Ca va ?" + expect(page).to have_unchecked_field "Commune" + expect(page).to have_unchecked_field "Siret" + expect(page).to have_unchecked_field "(Bloc répétable Amis) – Prénom" + end +end diff --git a/spec/controllers/instructeurs/export_templates_controller_spec.rb b/spec/controllers/instructeurs/export_templates_controller_spec.rb index 4576090fc..32fba6ba8 100644 --- a/spec/controllers/instructeurs/export_templates_controller_spec.rb +++ b/spec/controllers/instructeurs/export_templates_controller_spec.rb @@ -86,6 +86,42 @@ describe Instructeurs::ExportTemplatesController, type: :controller do expect(ExportTemplate.last.pjs).to match_array([]) end end + + context 'with tabular params' do + let(:procedure) do + create( + :procedure, instructeurs: [instructeur], + types_de_champ_public: [{ type: :text, libelle: 'un texte', stable_id: 1 }] + ) + end + + let(:exported_columns) do + [ + { id: procedure.find_column(label: 'Demandeur').id, libelle: 'Demandeur' }, + { id: procedure.find_column(label: 'Date du dernier évènement').id, libelle: 'Date du dernier évènement' } + ].map(&:to_json) + end + + let(:create_params) do + { + name: "ExportODS", + kind: "ods", + groupe_instructeur_id: groupe_instructeur.id, + export_pdf: item_params(text: "export"), + dossier_folder: item_params(text: "dossier"), + exported_columns: + } + end + + context 'with valid params' do + it 'redirect to some page' do + subject + expect(response).to redirect_to(exports_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 + end + end end describe '#edit' do @@ -146,6 +182,35 @@ describe Instructeurs::ExportTemplatesController, type: :controller do expect(flash.alert).to be_present end end + + context 'for tabular' do + let(:exported_columns) do + [ + { id: procedure.find_column(label: 'Demandeur').id, libelle: 'Demandeur' }, + { id: procedure.find_column(label: 'Date du dernier évènement').id, libelle: 'Date du dernier évènement' } + ].map(&:to_json) + end + + let(:export_template_params) do + { + name: "ExportODS", + kind: "ods", + groupe_instructeur_id: groupe_instructeur.id, + export_pdf: item_params(text: "export"), + dossier_folder: item_params(text: "dossier"), + exported_columns: + } + end + + context 'with valid params' do + it 'redirect to some page' do + subject + expect(response).to redirect_to(exports_instructeur_procedure_path(procedure)) + expect(flash.notice).to eq "Le modèle d'export ExportODS a bien été modifié" + expect(ExportTemplate.last.exported_columns.map(&:libelle)).to match_array ['Demandeur', 'Date du dernier évènement'] + end + end + end end describe '#destroy' do diff --git a/spec/models/export_template_tabular_spec.rb b/spec/models/export_template_tabular_spec.rb new file mode 100644 index 000000000..56518ae1e --- /dev/null +++ b/spec/models/export_template_tabular_spec.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +describe ExportTemplate do + let(:groupe_instructeur) { create(:groupe_instructeur, procedure:) } + let(:export_template) { build(:export_template, kind: 'csv', groupe_instructeur:) } + let(:tabular_export_template) { build(:tabular_export_template, groupe_instructeur:) } + let(:procedure) { create(:procedure_with_dossiers, :published, types_de_champ_public:, for_individual:) } + let(:for_individual) { true } + let(:types_de_champ_public) do + [ + { type: :text, libelle: "Ca va ?", mandatory: true, stable_id: 1 }, + { type: :communes, libelle: "Commune", mandatory: true, stable_id: 17 }, + { type: :siret, libelle: 'siret', stable_id: 20 }, + { type: :repetition, mandatory: true, stable_id: 7, libelle: "Champ répétable", children: [{ type: 'text', libelle: 'Qqchose à rajouter?', stable_id: 8 }] } + ] + end + + describe '#exported_columns=' do + it 'is assignable/readable with ExportedColumn object' do + expect do + export_template.exported_columns = [ + ExportedColumn.new(libelle: 'Ça va ?', column: procedure.find_column(label: "Ca va ?")) + ] + export_template.save! + export_template.exported_columns + end.not_to raise_error + end + it 'create exported_column' do + export_template.exported_columns = [ + ExportedColumn.new(libelle: 'Ça va ?', column: procedure.find_column(label: "Ca va ?")) + ] + export_template.save! + expect(export_template.exported_columns.size).to eq 1 + end + + context 'when there is a previous revision with a renamed tdc' do + context 'with already column in export template' do + let(:previous_tdc) { procedure.published_revision.types_de_champ_public.find_by(stable_id: 1) } + let(:changed_tdc) { { libelle: "Ca roule ?" } } + + context 'with already column in export template' do + before do + export_template.exported_columns = [ + ExportedColumn.new(libelle: 'Ça va ?', column: procedure.find_column(label: "Ca va ?")) + ] + export_template.save! + + type_de_champ = procedure.draft_revision.find_and_ensure_exclusive_use(previous_tdc.stable_id) + type_de_champ.update(changed_tdc) + procedure.publish_revision! + end + + it 'update columns with original libelle for champs with new revision' do + Current.procedure_columns = {} + procedure.reload + export_template.reload + expect(export_template.exported_columns.find { _1.column.stable_id.to_s == "1" }.libelle).to eq('Ça va ?') + end + end + end + context 'without columns in export template' do + let(:previous_tdc) { procedure.published_revision.types_de_champ_public.find_by(stable_id: 1) } + let(:changed_tdc) { { libelle: "Ca roule ?" } } + + before do + type_de_champ = procedure.draft_revision.find_and_ensure_exclusive_use(previous_tdc.stable_id) + type_de_champ.update(changed_tdc) + procedure.publish_revision! + + export_template.exported_columns = [ + ExportedColumn.new(libelle: 'Ça roule ?', column: procedure.find_column(label: "Ca roule ?")) + ] + export_template.save! + end + + it 'update columns with original libelle for champs with new revision' do + Current.procedure_columns = {} + procedure.reload + export_template.reload + expect(export_template.exported_columns.find { _1.column.stable_id.to_s == "1" }.libelle).to eq('Ça roule ?') + end + end + end + end +end diff --git a/spec/system/instructeurs/procedure_export_tabular_spec.rb b/spec/system/instructeurs/procedure_export_tabular_spec.rb new file mode 100644 index 000000000..326bdbc30 --- /dev/null +++ b/spec/system/instructeurs/procedure_export_tabular_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +describe "procedure exports" do + let(:instructeur) { create(:instructeur) } + let(:procedure) { create(:procedure, :published, types_de_champ_public:, instructeurs: [instructeur]) } + let(:types_de_champ_public) { [{ type: :text }] } + before { login_as(instructeur.user, scope: :user) } + + scenario "create an export_template tabular and u", js: true do + Flipper.enable(:export_template, procedure) + visit instructeur_procedure_path(procedure) + + click_on "Voir les exports et modèles d'export" + + click_on "Modèles d'export" + + click_on "Créer un modèle d'export tabulaire" + + 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 + + # check if all usager colonnes are selected + # + click_on 'Mon modèle' + + within '#informations-usager-fieldset' do + expect(all('input[type=checkbox]').all?(&:checked?)).to be_truthy + end + + within '#informations-dossier-fieldset' do + expect(all('input[type=checkbox]').all?(&:checked?)).to be_truthy + end + + # uncheck checkboxes + find("#informations-dossier-fieldset label", text: "Tout sélectionner").click + within '#informations-dossier-fieldset' do + expect(all('input[type=checkbox]').none?(&:checked?)).to be_truthy + end + end +end diff --git a/spec/system/routing/rules_full_scenario_spec.rb b/spec/system/routing/rules_full_scenario_spec.rb index b38bbba68..56e1c7942 100644 --- a/spec/system/routing/rules_full_scenario_spec.rb +++ b/spec/system/routing/rules_full_scenario_spec.rb @@ -209,7 +209,7 @@ describe 'The routing with rules', js: true do ## on the dossiers list click_on procedure.libelle expect(page).to have_current_path(instructeur_procedure_path(procedure)) - expect(find('.fr-tabs')).to have_css('span.notifications') + expect(find('nav.fr-tabs')).to have_css('span.notifications') ## on the dossier itself click_on 'suivi'