diff --git a/app/components/attachment/edit_component.rb b/app/components/attachment/edit_component.rb
new file mode 100644
index 000000000..5ae74730c
--- /dev/null
+++ b/app/components/attachment/edit_component.rb
@@ -0,0 +1,92 @@
+# Display a widget for uploading, editing and deleting a file attachment
+class Attachment::EditComponent < ApplicationComponent
+ def initialize(form:, attached_file:, accept: nil, template: nil, user_can_destroy: false, direct_upload: true)
+ @form = form
+ @attached_file = attached_file
+ @accept = accept
+ @template = template
+ @user_can_destroy = user_can_destroy
+ @direct_upload = direct_upload
+ end
+
+ attr_reader :template, :form
+
+ def self.text(form, file)
+ new(form: form, attached_file: file, user_can_destroy: true)
+ end
+
+ def self.image(form, file, direct_upload = true)
+ new(form: form,
+ attached_file: file,
+ accept: 'image/png, image/jpg, image/jpeg',
+ user_can_destroy: true,
+ direct_upload: direct_upload)
+ end
+
+ def user_can_destroy?
+ @user_can_destroy
+ end
+
+ def attachment
+ @attached_file.attachment
+ end
+
+ def attachment_path
+ helpers.attachment_path attachment.id, { signed_id: attachment.blob.signed_id }
+ end
+
+ def attachment_id
+ @attachment_id ||= attachment ? attachment.id : SecureRandom.uuid
+ end
+
+ def attachment_input_class
+ "attachment-input-#{attachment_id}"
+ end
+
+ def persisted?
+ attachment&.persisted?
+ end
+
+ def champ
+ @form.object.is_a?(Champ) ? @form.object : nil
+ end
+
+ def file_field_options
+ {
+ class: "attachment-input #{attachment_input_class} #{'hidden' if persisted?}",
+ accept: @accept,
+ direct_upload: @direct_upload,
+ id: champ&.input_id,
+ aria: { describedby: champ&.describedby_id },
+ data: { auto_attach_url: helpers.auto_attach_url(form, form.object) }
+ }
+ end
+
+ def file_field_name
+ @attached_file.name
+ end
+
+ def remove_button_options
+ {
+ role: 'button',
+ class: 'button small danger',
+ data: { turbo_method: :delete }
+ }
+ end
+
+ def retry_button_options
+ {
+ type: 'button',
+ class: 'button attachment-error-retry',
+ data: { input_target: ".#{attachment_input_class}", action: 'autosave#onClickRetryButton' }
+ }
+ end
+
+ def replace_button_options
+ {
+ type: 'button',
+ class: 'button small',
+ data: { toggle_target: ".#{attachment_input_class}" }
+ }
+ end
+end
diff --git a/app/components/attachment/edit_component/edit_component.en.yml b/app/components/attachment/edit_component/edit_component.en.yml
new file mode 100644
index 000000000..1491cafbf
--- /dev/null
+++ b/app/components/attachment/edit_component/edit_component.en.yml
@@ -0,0 +1,2 @@
+---
+en:
diff --git a/app/components/attachment/edit_component/edit_component.fr.yml b/app/components/attachment/edit_component/edit_component.fr.yml
new file mode 100644
index 000000000..09f6db466
--- /dev/null
+++ b/app/components/attachment/edit_component/edit_component.fr.yml
@@ -0,0 +1,2 @@
+---
+fr:
diff --git a/app/components/attachment/edit_component/edit_component.html.haml b/app/components/attachment/edit_component/edit_component.html.haml
new file mode 100644
index 000000000..ef538b7e4
--- /dev/null
+++ b/app/components/attachment/edit_component/edit_component.html.haml
@@ -0,0 +1,27 @@
+.attachment
+ - if template&.attached?
+ %p.mb-1
+ Veuillez télécharger, remplir et joindre
+ = link_to('le modèle suivant', url_for(template), target: '_blank', rel: 'noopener')
+
+ - if persisted?
+ .attachment-actions{ id: dom_id(attachment, :actions) }
+ .attachment-action
+ = render Attachment::ShowComponent.new(attachment: attachment, user_can_upload: true)
+ - if user_can_destroy?
+ .attachment-action{ "data-turbo": "true" }
+ = link_to('Supprimer', attachment_path, **remove_button_options)
+ .attachment-action
+ = button_tag('Remplacer', **replace_button_options)
+
+ .attachment-error.hidden
+ .attachment-error-message
+ %p.attachment-error-title
+ Une erreur s’est produite pendant l’envoi du fichier.
+ %p.attachment-error-description
+ Une erreur inconnue s'est produite pendant l'envoi du fichier
+ = button_tag(**retry_button_options) do
+ %span.icon.retry
+ Ré-essayer
+
+ = form.file_field(file_field_name, **file_field_options)
diff --git a/app/components/attachment/show_component.rb b/app/components/attachment/show_component.rb
new file mode 100644
index 000000000..c62894aaa
--- /dev/null
+++ b/app/components/attachment/show_component.rb
@@ -0,0 +1,27 @@
+class Attachment::ShowComponent < ApplicationComponent
+ def initialize(attachment:, user_can_upload: false)
+ @attachment = attachment
+ @user_can_upload = user_can_upload
+ end
+
+ attr_reader :attachment
+
+ def user_can_upload?
+ @user_can_upload
+ end
+
+ def should_display_link?
+ (attachment.virus_scanner.safe? || !attachment.virus_scanner.started?) && !attachment.watermark_pending?
+ end
+
+ def attachment_path
+ helpers.attachment_path(attachment.id, { signed_id: attachment.blob.signed_id, user_can_upload: user_can_upload? })
+ end
+
+ def poll_controller_options
+ {
+ controller: 'turbo-poll',
+ turbo_poll_url_value: attachment_path
+ }
+ end
+end
diff --git a/app/components/attachment/show_component/show_component.en.yml b/app/components/attachment/show_component/show_component.en.yml
new file mode 100644
index 000000000..1491cafbf
--- /dev/null
+++ b/app/components/attachment/show_component/show_component.en.yml
@@ -0,0 +1,2 @@
+---
+en:
diff --git a/app/components/attachment/show_component/show_component.fr.yml b/app/components/attachment/show_component/show_component.fr.yml
new file mode 100644
index 000000000..09f6db466
--- /dev/null
+++ b/app/components/attachment/show_component/show_component.fr.yml
@@ -0,0 +1,2 @@
+---
+fr:
diff --git a/app/views/shared/attachment/_show.html.haml b/app/components/attachment/show_component/show_component.html.haml
similarity index 55%
rename from app/views/shared/attachment/_show.html.haml
rename to app/components/attachment/show_component/show_component.html.haml
index 4437724a7..39925adab 100644
--- a/app/views/shared/attachment/_show.html.haml
+++ b/app/components/attachment/show_component/show_component.html.haml
@@ -1,12 +1,5 @@
-- should_display_link = (attachment.virus_scanner.safe? || !attachment.virus_scanner.started?) && !attachment.watermark_pending?
-- user_can_upload = defined?(user_can_upload) ? user_can_upload : false
-- if should_display_link
- - attachment_check_url = false
-- else
- - attachment_check_url = attachment_url(attachment.id, { signed_id: attachment.blob.signed_id, user_can_upload: user_can_upload })
-
-.attachment-link{ 'data-attachment-id': attachment.id, 'data-attachment-poll-url': attachment_check_url }
- - if should_display_link
+.attachment-link{ id: dom_id(attachment, :show) }
+ - if should_display_link?
= link_to url_for(attachment.blob), target: '_blank', rel: 'noopener', title: "Télécharger la pièce jointe" do
%span.icon.attached
= attachment.filename.to_s
@@ -14,22 +7,23 @@
(ce fichier n’a pas été analysé par notre antivirus, téléchargez-le avec précaution)
- else
+ %span{ data: poll_controller_options }
= attachment.filename.to_s
- if attachment.virus_scanner.pending?
(analyse antivirus en cours
- = link_to "rafraichir", request.path, data: { 'attachment-refresh': true }
+ = link_to "rafraichir", attachment_path, data: { action: 'turbo-poll#refresh' }
)
- elsif attachment.watermark_pending?
(traitement de la pièce en cours
- = link_to "rafraichir", request.path, data: { 'attachment-refresh': true }
+ = link_to "rafraichir", attachment_path, data: { action: 'turbo-poll#refresh' }
)
- elsif attachment.virus_scanner.infected?
- - if user_can_upload
+ - if user_can_upload?
(virus détecté, merci d’envoyer un autre fichier)
- else
(virus détecté, le téléchargement de ce fichier est bloqué)
- elsif attachment.virus_scanner.corrupt?
- - if user_can_upload
+ - if user_can_upload?
(le fichier est corrompu, merci d’envoyer un autre fichier)
- else
(le fichier est corrompu, le téléchargement est bloqué)
diff --git a/app/components/dossiers/export_component.rb b/app/components/dossiers/export_component.rb
new file mode 100644
index 000000000..96e4f5d7a
--- /dev/null
+++ b/app/components/dossiers/export_component.rb
@@ -0,0 +1,49 @@
+class Dossiers::ExportComponent < ApplicationComponent
+ def initialize(procedure:, exports:, statut:, count:)
+ @procedure = procedure
+ @exports = exports
+ @statut = statut
+ @count = count
+ end
+
+ def exports
+ helpers.exports_list(@exports, @statut)
+ end
+
+ def download_export_path(export_format:, force_export: false, no_progress_notification: nil)
+ download_export_instructeur_procedure_path(@procedure,
+ export_format: export_format,
+ statut: @statut,
+ force_export: force_export,
+ no_progress_notification: no_progress_notification)
+ end
+
+ def refresh_button_options(export)
+ {
+ title: t(".everything_short", export_format: ".#{export.format}"),
+ class: "button small",
+ style: "padding-right: 2px"
+ }
+ end
+
+ def ready_link_label(export)
+ t(".everything_ready_html",
+ export_time: helpers.time_ago_in_words(export.updated_at),
+ export_format: ".#{export.format}")
+ end
+
+ def pending_label(export)
+ t(".everything_pending_html",
+ export_time: time_ago_in_words(export.created_at),
+ export_format: ".#{export.format}")
+ end
+
+ def poll_controller_options(export)
+ {
+ controller: 'turbo-poll',
+ turbo_poll_url_value: download_export_path(export_format: export.format, no_progress_notification: true),
+ turbo_poll_interval_value: 6000,
+ turbo_poll_max_checks_value: 10
+ }
+ end
+end
diff --git a/app/components/dossiers/export_component/export_component.en.yml b/app/components/dossiers/export_component/export_component.en.yml
new file mode 100644
index 000000000..c548a2b08
--- /dev/null
+++ b/app/components/dossiers/export_component/export_component.en.yml
@@ -0,0 +1,12 @@
+---
+en:
+ everything_csv_html: Ask an export in format .csv
(only folders, without repeatable fields)
+ everything_xlsx_html: Ask an export in format .xlsx
+ everything_ods_html: Ask an export in format .ods
+ everything_zip_html: Ask an export in format .zip
+ everything_short: Ask an export in format%{export_format}
+ everything_pending_html: Ask an export in format %{export_format} is being generated
(ask %{export_time} ago)
+ everything_ready_html: Download the export in format %{export_format}
(generated %{export_time} ago)
+ download:
+ one: Download a file
+ other: Download %{count} files
diff --git a/app/components/dossiers/export_component/export_component.fr.yml b/app/components/dossiers/export_component/export_component.fr.yml
new file mode 100644
index 000000000..7e185ccda
--- /dev/null
+++ b/app/components/dossiers/export_component/export_component.fr.yml
@@ -0,0 +1,12 @@
+---
+fr:
+ everything_csv_html: Demander un export au format .csv
(uniquement les dossiers, sans les champs répétables)
+ everything_xlsx_html: Demander un export au format .xlsx
+ everything_ods_html: Demander un export au format .ods
+ everything_zip_html: Demander un export au format .zip
+ everything_short: Demander un export au format %{export_format}
+ everything_pending_html: Un export au format %{export_format} est en train d’être généré
(demandé il y a %{export_time})
+ everything_ready_html: Télécharger l’export au format %{export_format}
(généré il y a %{export_time})
+ download:
+ one: Télécharger un dossier
+ other: Télécharger %{count} dossiers
diff --git a/app/components/dossiers/export_component/export_component.html.haml b/app/components/dossiers/export_component/export_component.html.haml
new file mode 100644
index 000000000..aad58e0c5
--- /dev/null
+++ b/app/components/dossiers/export_component/export_component.html.haml
@@ -0,0 +1,22 @@
+%span.dropdown{ data: { controller: 'menu-button' } }
+ %button.button.dropdown-button{ data: { menu_button_target: 'button' } }
+ = t(".download", count: @count)
+ #download-menu.dropdown-content.fade-in-down{ style: 'width: 450px', data: { menu_button_target: 'menu' } }
+ %ul.dropdown-items{ 'data-turbo': 'true' }
+ - exports.each do |item|
+ - export = item[:export]
+ %li
+ - if export.nil?
+ // i18n-tasks-use t('.everything_csv_html')
+ // i18n-tasks-use t('.everything_xlsx_html')
+ // i18n-tasks-use t('.everything_ods_html')
+ // i18n-tasks-use t('.everything_zip_html')
+ = link_to t(".everything_#{item[:format]}_html"), download_export_path(export_format: item[:format]), data: { turbo_method: :post }
+ - elsif export.ready?
+ = link_to ready_link_label(export), export.file.service_url, target: "_blank", rel: "noopener"
+ - if export.old?
+ = button_to download_export_path(export_format: export.format, force_export: true), **refresh_button_options(export) do
+ .icon.retry
+ - else
+ %span{ data: poll_controller_options(export) }
+ = pending_label(export)
diff --git a/app/components/dossiers/message_component/message_component.html.haml b/app/components/dossiers/message_component/message_component.html.haml
index c19f78791..622e4d09e 100644
--- a/app/components/dossiers/message_component/message_component.html.haml
+++ b/app/components/dossiers/message_component/message_component.html.haml
@@ -18,7 +18,7 @@
- if commentaire.piece_jointe.attached?
.attachment-link
- = render partial: "shared/attachment/show", locals: { attachment: commentaire.piece_jointe.attachment }
+ = render Attachment::ShowComponent.new(attachment: commentaire.piece_jointe.attachment)
- if show_reply_button?
= button_tag type: 'button', class: 'button small message-answer-button', onclick: 'document.querySelector("#commentaire_body").focus()' do
diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb
index a3a2fc471..be5d3ace2 100644
--- a/app/controllers/attachments_controller.rb
+++ b/app/controllers/attachments_controller.rb
@@ -7,15 +7,19 @@ class AttachmentsController < ApplicationController
@user_can_upload = params[:user_can_upload]
respond_to do |format|
- format.js
+ format.turbo_stream
format.html { redirect_back(fallback_location: root_url) }
end
end
def destroy
- attachment = @blob.attachments.find(params[:id])
- @attachment_id = attachment.id
- attachment.purge_later
- flash.now.notice = 'La pièce jointe a bien été supprimée.'
+ @attachment = @blob.attachments.find(params[:id])
+ @attachment.purge_later
+ flash.notice = 'La pièce jointe a bien été supprimée.'
+
+ respond_to do |format|
+ format.turbo_stream
+ format.html { redirect_back(fallback_location: root_url) }
+ end
end
end
diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb
index cf32e1167..379119141 100644
--- a/app/controllers/instructeurs/procedures_controller.rb
+++ b/app/controllers/instructeurs/procedures_controller.rb
@@ -156,7 +156,7 @@ module Instructeurs
if export.ready?
respond_to do |format|
- format.js do
+ format.turbo_stream do
@procedure = procedure
@statut = export_options[:statut]
@dossiers_count = export.count
@@ -172,7 +172,7 @@ module Instructeurs
respond_to do |format|
notice_message = "Nous générons cet export. Veuillez revenir dans quelques minutes pour le télécharger."
- format.js do
+ format.turbo_stream do
@procedure = procedure
@statut = export_options[:statut]
@dossiers_count = export.count
diff --git a/app/helpers/attachment_upload_helper.rb b/app/helpers/attachment_upload_helper.rb
deleted file mode 100644
index 0edcc7cb9..000000000
--- a/app/helpers/attachment_upload_helper.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module AttachmentUploadHelper
- def image_upload_and_render(form, file, direct_upload = nil)
- render 'shared/attachment/edit', {
- form: form,
- attached_file: file,
- accept: 'image/png, image/jpg, image/jpeg',
- user_can_destroy: true,
- direct_upload: direct_upload
- }
- end
-
- def text_upload_and_render(form, file)
- render 'shared/attachment/edit', {
- form: form,
- attached_file: file,
- user_can_destroy: true
- }
- end
-end
diff --git a/app/javascript/controllers/index.ts b/app/javascript/controllers/index.ts
index 133d83ea7..f235d0069 100644
--- a/app/javascript/controllers/index.ts
+++ b/app/javascript/controllers/index.ts
@@ -1,18 +1,20 @@
import { Application } from '@hotwired/stimulus';
-import { ReactController } from './react_controller';
-import { TurboEventController } from './turbo_event_controller';
-import { GeoAreaController } from './geo_area_controller';
-import { TurboInputController } from './turbo_input_controller';
import { AutosaveController } from './autosave_controller';
import { AutosaveStatusController } from './autosave_status_controller';
+import { GeoAreaController } from './geo_area_controller';
import { MenuButtonController } from './menu_button_controller';
+import { ReactController } from './react_controller';
+import { TurboEventController } from './turbo_event_controller';
+import { TurboInputController } from './turbo_input_controller';
+import { TurboPollController } from './turbo_poll_controller';
const Stimulus = Application.start();
+Stimulus.register('autosave-status', AutosaveStatusController);
+Stimulus.register('autosave', AutosaveController);
+Stimulus.register('geo-area', GeoAreaController);
+Stimulus.register('menu-button', MenuButtonController);
Stimulus.register('react', ReactController);
Stimulus.register('turbo-event', TurboEventController);
-Stimulus.register('geo-area', GeoAreaController);
Stimulus.register('turbo-input', TurboInputController);
-Stimulus.register('autosave', AutosaveController);
-Stimulus.register('autosave-status', AutosaveStatusController);
-Stimulus.register('menu-button', MenuButtonController);
+Stimulus.register('turbo-poll', TurboPollController);
diff --git a/app/javascript/controllers/turbo_poll_controller.ts b/app/javascript/controllers/turbo_poll_controller.ts
new file mode 100644
index 000000000..abf249416
--- /dev/null
+++ b/app/javascript/controllers/turbo_poll_controller.ts
@@ -0,0 +1,94 @@
+import { httpRequest } from '@utils';
+
+import { ApplicationController } from './application_controller';
+
+const DEFAULT_POLL_INTERVAL = 3000;
+const DEFAULT_MAX_CHECKS = 5;
+
+// Periodically check the state of a URL.
+//
+// Each time the given URL is requested, a turbo-stream is rendered, causing the state to be refreshed.
+//
+// This is used mainly to refresh attachments during the anti-virus check,
+// but also to refresh the state of a pending spreadsheet export.
+export class TurboPollController extends ApplicationController {
+ static values = {
+ url: String,
+ maxChecks: { type: Number, default: DEFAULT_MAX_CHECKS },
+ interval: { type: Number, default: DEFAULT_POLL_INTERVAL }
+ };
+
+ declare readonly urlValue: string;
+ declare readonly intervalValue: number;
+ declare readonly maxChecksValue: number;
+
+ #timer?: number;
+ #abortController?: AbortController;
+
+ connect(): void {
+ const state = this.nextState();
+ if (state) {
+ this.schedule(state);
+ }
+ }
+
+ disconnect(): void {
+ this.cancel();
+ }
+
+ refresh() {
+ this.cancel();
+ this.#abortController = new AbortController();
+
+ httpRequest(this.urlValue, { signal: this.#abortController.signal })
+ .turbo()
+ .catch(() => null);
+ }
+
+ private schedule(state: PollState): void {
+ this.cancel();
+ this.#timer = setTimeout(() => {
+ this.refresh();
+ }, state.interval);
+ }
+
+ private cancel(): void {
+ clearTimeout(this.#timer);
+ this.#abortController?.abort();
+ this.#abortController = window.AbortController
+ ? new AbortController()
+ : undefined;
+ }
+
+ private nextState(): PollState | false {
+ const state = pollers.get(this.urlValue);
+ if (!state) {
+ return this.resetState();
+ }
+ state.interval *= 1.5;
+ state.checks += 1;
+ if (state.checks <= this.maxChecksValue) {
+ return state;
+ } else {
+ this.resetState();
+ return false;
+ }
+ }
+
+ private resetState(): PollState {
+ const state = {
+ interval: this.intervalValue,
+ checks: 0
+ };
+ pollers.set(this.urlValue, state);
+ return state;
+ }
+}
+
+type PollState = {
+ interval: number;
+ checks: number;
+};
+
+// We keep a global state of the pollers. It will be reset on every page change.
+const pollers = new Map();
diff --git a/app/views/administrateurs/attestation_templates/_informations.html.haml b/app/views/administrateurs/attestation_templates/_informations.html.haml
index 2b28b1b1a..397d2c57a 100644
--- a/app/views/administrateurs/attestation_templates/_informations.html.haml
+++ b/app/views/administrateurs/attestation_templates/_informations.html.haml
@@ -25,7 +25,7 @@
= tag[:description]
%h3.header-subsection Logo de l'attestation
-= image_upload_and_render f, @attestation_template.logo, false
+= render Attachment::EditComponent.image(f, @attestation_template.logo, false)
%p.notice
Formats acceptés : JPG / JPEG / PNG.
@@ -33,7 +33,7 @@
Dimensions conseillées : au minimum 500 px de largeur ou de hauteur, poids maximum : 0,5 Mo.
%h3.header-subsection Tampon de l'attestation
-= image_upload_and_render f, @attestation_template.signature, false
+= render Attachment::EditComponent.image(f, @attestation_template.signature, false)
%p.notice
Formats acceptés : JPG / JPEG / PNG.
diff --git a/app/views/administrateurs/procedures/_informations.html.haml b/app/views/administrateurs/procedures/_informations.html.haml
index 858673cbd..6d3eda15d 100644
--- a/app/views/administrateurs/procedures/_informations.html.haml
+++ b/app/views/administrateurs/procedures/_informations.html.haml
@@ -20,7 +20,7 @@
= f.select :zone_id, grouped_options_for_zone
%h3.header-subsection Logo de la démarche
-= image_upload_and_render f, @procedure.logo
+= render Attachment::EditComponent.image(f, @procedure.logo)
%h3.header-subsection Conservation des données
= f.label :duree_conservation_dossiers_dans_ds do
@@ -55,7 +55,7 @@
= f.text_field :cadre_juridique, class: 'form-control', placeholder: 'https://www.legifrance.gouv.fr/'
= f.label :deliberation, 'Importer le texte'
-= text_upload_and_render f, @procedure.deliberation
+= render Attachment::EditComponent.text(f, @procedure.deliberation)
%h3.header-subsection
RGPD
@@ -73,7 +73,7 @@
%p.notice
Formats acceptés : .doc, .odt, .pdf, .ppt, .pptx
- notice = @procedure.notice
-= text_upload_and_render f, @procedure.notice
+= render Attachment::EditComponent.text(f, @procedure.notice)
- if !@procedure.locked?
%h3.header-subsection À qui s’adresse ma démarche ?
diff --git a/app/views/attachments/destroy.js.erb b/app/views/attachments/destroy.js.erb
deleted file mode 100644
index 0d4b5e5ff..000000000
--- a/app/views/attachments/destroy.js.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= render_flash(timeout: 5000, sticky: true) %>
-<%= remove_element(".attachment-actions-#{@attachment_id}") %>
-<%= show_element(".attachment-input-#{@attachment_id}") %>
diff --git a/app/views/attachments/destroy.turbo_stream.haml b/app/views/attachments/destroy.turbo_stream.haml
new file mode 100644
index 000000000..323dd8f03
--- /dev/null
+++ b/app/views/attachments/destroy.turbo_stream.haml
@@ -0,0 +1,2 @@
+= turbo_stream.remove dom_id(@attachment, :actions)
+= turbo_stream.show_all ".attachment-input-#{@attachment.id}"
diff --git a/app/views/attachments/show.js.erb b/app/views/attachments/show.js.erb
deleted file mode 100644
index 0a58c0af5..000000000
--- a/app/views/attachments/show.js.erb
+++ /dev/null
@@ -1,8 +0,0 @@
-<%= render_to_element(".attachment-link[data-attachment-id=\"#{@attachment.id}\"]",
- partial: 'shared/attachment/show',
- outer: true,
- locals: { attachment: @attachment, user_can_upload: @user_can_upload }) %>
-
-<% if @attachment.virus_scanner.pending? || @attachment.watermark_pending? %>
- <%= fire_event('attachment:update', { url: attachment_url(@attachment.id, { signed_id: @attachment.blob.signed_id, user_can_upload: @user_can_upload }) }.to_json ) %>
-<% end %>
diff --git a/app/views/attachments/show.turbo_stream.haml b/app/views/attachments/show.turbo_stream.haml
new file mode 100644
index 000000000..dc7cd008f
--- /dev/null
+++ b/app/views/attachments/show.turbo_stream.haml
@@ -0,0 +1,2 @@
+= turbo_stream.replace dom_id(@attachment, :show) do
+ = render Attachment::ShowComponent.new(attachment: @attachment, user_can_upload: @user_can_upload)
diff --git a/app/views/experts/avis/instruction.html.haml b/app/views/experts/avis/instruction.html.haml
index 3c0673547..9e904d26b 100644
--- a/app/views/experts/avis/instruction.html.haml
+++ b/app/views/experts/avis/instruction.html.haml
@@ -12,12 +12,12 @@
%p.introduction= @avis.introduction
- if @avis.introduction_file.attached?
- = render partial: 'shared/attachment/show', locals: { attachment: @avis.introduction_file.attachment }
+ = render Attachment::ShowComponent.new(attachment: @avis.introduction_file.attachment)
%br/
= form_for @avis, url: expert_avis_path(@avis.procedure, @avis), html: { class: 'form', data: { persisted_content_id: @avis.id } } do |f|
= f.text_area :answer, rows: 3, placeholder: 'Votre avis', required: true, class: 'persisted-input'
- = text_upload_and_render f, @avis.piece_justificative_file
+ = render Attachment::EditComponent.text(f, @avis.piece_justificative_file)
.flex.justify-between.align-baseline
%p.confidentiel.flex
diff --git a/app/views/experts/avis/shared/avis/_form.html.haml b/app/views/experts/avis/shared/avis/_form.html.haml
index a1bcf1fac..00df6b934 100644
--- a/app/views/experts/avis/shared/avis/_form.html.haml
+++ b/app/views/experts/avis/shared/avis/_form.html.haml
@@ -7,7 +7,7 @@
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true
%p.tab-title Ajouter une pièce jointe
.form-group
- = text_upload_and_render f, avis.introduction_file
+ = render Attachment::EditComponent.text(f, avis.introduction_file)
- if linked_dossiers.present?
= f.check_box :invite_linked_dossiers, {}, true, false
diff --git a/app/views/experts/shared/avis/_form.html.haml b/app/views/experts/shared/avis/_form.html.haml
index 84aa541ad..1430c83ca 100644
--- a/app/views/experts/shared/avis/_form.html.haml
+++ b/app/views/experts/shared/avis/_form.html.haml
@@ -14,7 +14,7 @@
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true, class: 'persisted-input'
%p.tab-title Ajouter une pièce jointe
.form-group
- = text_upload_and_render f, avis.introduction_file
+ = render Attachment::EditComponent.text(f, avis.introduction_file)
- if linked_dossiers.present?
= f.check_box :invite_linked_dossiers, {}, true, false
diff --git a/app/views/experts/shared/avis/_list.html.haml b/app/views/experts/shared/avis/_list.html.haml
index f9acf92cd..256c857ee 100644
--- a/app/views/experts/shared/avis/_list.html.haml
+++ b/app/views/experts/shared/avis/_list.html.haml
@@ -33,6 +33,6 @@
%span.waiting
= t('en_attente', scope: 'views.shared.avis')
- if avis.piece_justificative_file.attached?
- = render partial: 'shared/attachment/show', locals: { attachment: avis.piece_justificative_file.attachment }
+ = render Attachment::ShowComponent.new(attachment: avis.piece_justificative_file.attachment)
.answer-body
= simple_format(avis.answer)
diff --git a/app/views/instructeurs/avis/instruction.html.haml b/app/views/instructeurs/avis/instruction.html.haml
index 61d03c91b..db68c6ed8 100644
--- a/app/views/instructeurs/avis/instruction.html.haml
+++ b/app/views/instructeurs/avis/instruction.html.haml
@@ -12,12 +12,12 @@
%p.introduction= @avis.introduction
- if @avis.introduction_file.attached?
- = render partial: 'shared/attachment/show', locals: { attachment: @avis.introduction_file.attachment }
+ = render Attachment::ShowComponent.new(attachment: @avis.introduction_file.attachment)
%br/
= form_for @avis, url: instructeur_avis_path(@avis.procedure, @avis), html: { class: 'form' } do |f|
= f.text_area :answer, rows: 3, placeholder: 'Votre avis', required: true
- = text_upload_and_render f, @avis.piece_justificative_file
+ = render Attachment::EditComponent.text(f, @avis.piece_justificative_file)
.flex.justify-between.align-baseline
%p.confidentiel.flex
diff --git a/app/views/instructeurs/procedures/_dossiers_export.html.haml b/app/views/instructeurs/procedures/_dossiers_export.html.haml
deleted file mode 100644
index cffde1c1a..000000000
--- a/app/views/instructeurs/procedures/_dossiers_export.html.haml
+++ /dev/null
@@ -1,23 +0,0 @@
-%span.dropdown{ data: { controller: 'menu-button' } }
- %button.button.dropdown-button{ data: { menu_button_target: 'button' } }
- = t(".download", count: count)
- #download-menu.dropdown-content.fade-in-down{ style: 'width: 450px', data: { menu_button_target: 'menu' } }
- %ul.dropdown-items
- - exports_list(exports, statut).each do |item|
- - format = item[:format]
- - export = item[:export]
- %li
- - if export.nil?
- // i18n-tasks-use t('.everything_csv_html')
- // i18n-tasks-use t('.everything_xlsx_html')
- // i18n-tasks-use t('.everything_ods_html')
- // i18n-tasks-use t('.everything_zip_html')
- = link_to t(".everything_#{format}_html"), download_export_instructeur_procedure_path(procedure, statut: statut, export_format: format), remote: true
- - elsif export.ready?
- = link_to t(".everything_ready_html", export_time: time_ago_in_words(export.updated_at), export_format: ".#{format}"), export.file.service_url, target: "_blank", rel: "noopener"
- - if export.old?
- = button_to download_export_instructeur_procedure_path(procedure, export_format: format, statut: statut, force_export: true), class: "button small", style: "padding-right: 2px", title: t(".everything_short", export_format: ".#{format}"), remote: true, method: :get, params: { export_format: format, statut: statut, force_export: true } do
- .icon.retry
- - else
- %span{ 'data-export-poll-url': download_export_instructeur_procedure_path(procedure, export_format: format, statut: statut, no_progress_notification: true) }
- = t(".everything_pending_html", export_time: time_ago_in_words(export.created_at), export_format: ".#{format}")
diff --git a/app/views/instructeurs/procedures/download_export.js.erb b/app/views/instructeurs/procedures/download_export.js.erb
deleted file mode 100644
index ab489f92d..000000000
--- a/app/views/instructeurs/procedures/download_export.js.erb
+++ /dev/null
@@ -1,24 +0,0 @@
-<% if @can_download_dossiers %>
- <% if @statut.present? %>
- <%= render_to_element('.dossiers-export', partial: "dossiers_export", locals: { procedure: @procedure, exports: @exports, statut: @statut, count: @dossiers_count }) %>
- <% else %>
- <%= render_to_element('.procedure-actions', partial: "download_dossiers", locals: { procedure: @procedure, exports: @exports }) %>
- <% end %>
-<% end %>
-
-<% @exports.values.each do |exports| %>
- <% if @statut.present? %>
- <% export = exports[:statut][@statut] %>
- <% if export && !export.ready? %>
- <%= fire_event('export:update', { url: download_export_instructeur_procedure_path(@procedure, export_format: export.format, statut: export.statut, no_progress_notification: true) }.to_json) %>
- <% end %>
- <% else %>
- <% exports[:time_span_type].values.each do |export| %>
- <% if !export.ready? %>
- <%= fire_event('export:update', { url: download_export_instructeur_procedure_path(@procedure, export_format: export.format, time_span_type: export.time_span_type, no_progress_notification: true) }.to_json) %>
- <% end %>
- <% end %>
- <% end %>
-<% end %>
-
-<%= render_flash %>
diff --git a/app/views/instructeurs/procedures/download_export.turbo_stream.haml b/app/views/instructeurs/procedures/download_export.turbo_stream.haml
new file mode 100644
index 000000000..103a64e4f
--- /dev/null
+++ b/app/views/instructeurs/procedures/download_export.turbo_stream.haml
@@ -0,0 +1,3 @@
+- if @can_download_dossiers
+ = turbo_stream.update_all '.dossiers-export' do
+ = render Dossiers::ExportComponent.new(procedure: @procedure, exports: @exports, statut: @statut, count: @dossiers_count)
diff --git a/app/views/instructeurs/procedures/email_usagers.html.haml b/app/views/instructeurs/procedures/email_usagers.html.haml
index 5f0a5be1f..5373d9435 100644
--- a/app/views/instructeurs/procedures/email_usagers.html.haml
+++ b/app/views/instructeurs/procedures/email_usagers.html.haml
@@ -26,7 +26,7 @@
%p= message.body
.answer.flex.align-start
- if message.piece_jointe.present?
- = render partial: 'shared/attachment/show', locals: { attachment: message.piece_jointe.attachment }
+ = render Attachment::ShowComponent.new(attachment: message.piece_jointe.attachment)
- else
.page-title.center
%h2 Il n'y a aucun dossier en brouillon dans vos groupes instructeurs
diff --git a/app/views/instructeurs/procedures/show.html.haml b/app/views/instructeurs/procedures/show.html.haml
index b565fe51e..8c1090f38 100644
--- a/app/views/instructeurs/procedures/show.html.haml
+++ b/app/views/instructeurs/procedures/show.html.haml
@@ -63,7 +63,7 @@
= render partial: "dossiers_filter", locals: { procedure: @procedure, procedure_presentation: @procedure_presentation, current_filters: @current_filters, statut: @statut, displayed_fields_options: @displayed_fields_options }
- if @dossiers_count > 0
.dossiers-export
- = render partial: "dossiers_export", locals: { procedure: @procedure, exports: @exports, statut: @statut, count: @dossiers_count }
+ = render Dossiers::ExportComponent.new(procedure: @procedure, exports: @exports, statut: @statut, count: @dossiers_count)
%table.table.dossiers-table.hoverable
%thead
diff --git a/app/views/instructeurs/shared/avis/_form.html.haml b/app/views/instructeurs/shared/avis/_form.html.haml
index b82396296..4bd16c19c 100644
--- a/app/views/instructeurs/shared/avis/_form.html.haml
+++ b/app/views/instructeurs/shared/avis/_form.html.haml
@@ -21,7 +21,7 @@
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true, class: "persisted-input"
%p.tab-title Ajouter une pièce jointe
.form-group
- = text_upload_and_render f, avis.introduction_file
+ = render Attachment::EditComponent.text(f, avis.introduction_file)
- if linked_dossiers.present?
= f.check_box :invite_linked_dossiers, {}, true, false
diff --git a/app/views/instructeurs/shared/avis/_list.html.haml b/app/views/instructeurs/shared/avis/_list.html.haml
index fb1f6b032..8c1693569 100644
--- a/app/views/instructeurs/shared/avis/_list.html.haml
+++ b/app/views/instructeurs/shared/avis/_list.html.haml
@@ -41,11 +41,11 @@
|
= link_to(t('revoke', scope: 'helpers.label'), revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revoke', scope: 'helpers.confirmation', email: avis.expert.email) }, method: :patch)
- if avis.introduction_file.attached?
- = render partial: 'shared/attachment/show', locals: { attachment: avis.introduction_file.attachment }
+ = render Attachment::ShowComponent.new(attachment: avis.introduction_file.attachment)
.answer-body.mb-3
%p #{t('views.instructeurs.avis.introduction_file_explaination')} #{avis.claimant.email}
- if avis.piece_justificative_file.attached?
- = render partial: 'shared/attachment/show', locals: { attachment: avis.piece_justificative_file.attachment }
+ = render Attachment::ShowComponent.new(attachment: avis.piece_justificative_file.attachment)
.answer-body
= simple_format(avis.answer)
diff --git a/app/views/layouts/application.turbo_stream.haml b/app/views/layouts/application.turbo_stream.haml
index 343964e1f..accaad848 100644
--- a/app/views/layouts/application.turbo_stream.haml
+++ b/app/views/layouts/application.turbo_stream.haml
@@ -1,6 +1,6 @@
- if flash.any?
= turbo_stream.replace 'flash_messages', partial: 'layouts/flash_messages'
- = turbo_stream.hide 'flash_messages', delay: 10000
+ = turbo_stream.hide 'flash_messages', delay: 30000
- flash.clear
= yield
diff --git a/app/views/shared/attachment/_edit.html.haml b/app/views/shared/attachment/_edit.html.haml
deleted file mode 100644
index 358b1a3a3..000000000
--- a/app/views/shared/attachment/_edit.html.haml
+++ /dev/null
@@ -1,43 +0,0 @@
--# Display a widget for uploading, editing and deleting a file attachment
-
-- attachment = attached_file.attachment
-- attachment_id = attachment ? attachment.id : SecureRandom.uuid
-- persisted = attachment && attachment.persisted?
-- accept = defined?(accept) ? accept : nil
-- user_can_destroy = defined?(user_can_destroy) ? user_can_destroy : false
-- direct_upload = direct_upload != nil ? false : true
-- champ = form.object.is_a?(Champ) ? form.object : nil
-
-.attachment
- - if defined?(template) && template.attached?
- %p.mb-1
- Veuillez télécharger, remplir et joindre
- = link_to('le modèle suivant', url_for(template), target: '_blank', rel: 'noopener')
-
- - if persisted
- .attachment-actions{ class: "attachment-actions-#{attachment_id}" }
- .attachment-action
- = render partial: "shared/attachment/show", locals: { attachment: attachment, user_can_upload: true }
- - if user_can_destroy
- .attachment-action
- = link_to 'Supprimer', attachment_url(attachment.id, { signed_id: attachment.blob.signed_id }), remote: true, method: :delete, class: 'button small danger', data: { disable: true }, role: 'button'
- .attachment-action
- = button_tag 'Remplacer', type: 'button', class: 'button small', data: { 'toggle-target': ".attachment-input-#{attachment_id}" }
-
- .attachment-error.hidden
- .attachment-error-message
- %p.attachment-error-title
- Une erreur s’est produite pendant l’envoi du fichier.
- %p.attachment-error-description
- Une erreur inconnue s'est produite pendant l'envoi du fichier
- = button_tag type: 'button', class: 'button attachment-error-retry', data: { 'input-target': ".attachment-input-#{attachment_id}", action: 'autosave#onClickRetryButton' } do
- %span.icon.retry
- Ré-essayer
-
- = form.file_field attached_file.name,
- class: "attachment-input attachment-input-#{attachment_id} #{'hidden' if persisted}",
- accept: accept,
- direct_upload: direct_upload,
- id: champ&.input_id,
- aria: { describedby: champ&.describedby_id },
- data: { 'auto-attach-url': auto_attach_url(form, form.object) }
diff --git a/app/views/shared/champs/piece_justificative/_show.html.haml b/app/views/shared/champs/piece_justificative/_show.html.haml
index a9d7ae19c..c57cf367e 100644
--- a/app/views/shared/champs/piece_justificative/_show.html.haml
+++ b/app/views/shared/champs/piece_justificative/_show.html.haml
@@ -1,5 +1,5 @@
- pj = champ.piece_justificative_file
- if pj.attached?
- = render partial: "shared/attachment/show", locals: { attachment: pj.attachment }
+ = render Attachment::ShowComponent.new(attachment: pj.attachment)
- else
Pièce justificative non fournie
diff --git a/app/views/shared/dossiers/_infos_generales.html.haml b/app/views/shared/dossiers/_infos_generales.html.haml
index 36bfc77ed..aa27ea4e6 100644
--- a/app/views/shared/dossiers/_infos_generales.html.haml
+++ b/app/views/shared/dossiers/_infos_generales.html.haml
@@ -8,4 +8,4 @@
%td.libelle Justificatif :
%td
.action
- = render partial: 'shared/attachment/show', locals: { attachment: dossier.justificatif_motivation.attachment }
+ = render Attachment::ShowComponent.new(attachment: dossier.justificatif_motivation.attachment)
diff --git a/app/views/shared/dossiers/editable_champs/_piece_justificative.html.haml b/app/views/shared/dossiers/editable_champs/_piece_justificative.html.haml
index 0fc1f99c8..aa4c655b0 100644
--- a/app/views/shared/dossiers/editable_champs/_piece_justificative.html.haml
+++ b/app/views/shared/dossiers/editable_champs/_piece_justificative.html.haml
@@ -1,4 +1 @@
-= render 'shared/attachment/edit',
- { form: form,
- attached_file: champ.piece_justificative_file,
- template: champ.type_de_champ.piece_justificative_template, user_can_destroy: true }
+= render Attachment::EditComponent.new(form: form, attached_file: champ.piece_justificative_file, template: champ.type_de_champ.piece_justificative_template, user_can_destroy: true)
diff --git a/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml b/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml
index e4e65d20d..1ff8bd6d5 100644
--- a/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml
+++ b/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml
@@ -1,4 +1 @@
-= render 'shared/attachment/edit',
- { form: form,
- attached_file: champ.piece_justificative_file,
- user_can_destroy: true }
+= render Attachment::EditComponent.new(form: form, attached_file: champ.piece_justificative_file, user_can_destroy: true)
diff --git a/app/views/users/dossiers/show/_download_justificatif.html.haml b/app/views/users/dossiers/show/_download_justificatif.html.haml
index ce596c299..d7ecefab3 100644
--- a/app/views/users/dossiers/show/_download_justificatif.html.haml
+++ b/app/views/users/dossiers/show/_download_justificatif.html.haml
@@ -1,2 +1,2 @@
- if dossier.present? && dossier.justificatif_motivation.attached?
- = render partial: "shared/attachment/show", locals: { attachment: dossier.justificatif_motivation.attachment }
+ = render Attachment::ShowComponent.new(attachment: dossier.justificatif_motivation.attachment)
diff --git a/config/application.rb b/config/application.rb
index aaf6aa527..f73c01df2 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -87,5 +87,8 @@ module TPS
config.view_component.show_previews_source = true
config.view_component.default_preview_layout = 'component_preview'
config.view_component.preview_paths << "#{Rails.root}/spec/components/previews"
+
+ # see: https://viewcomponent.org/known_issues.html
+ config.view_component.use_global_output_buffer = true
end
end
diff --git a/config/locales/views/instructeurs/procedures/en.yml b/config/locales/views/instructeurs/procedures/en.yml
index fd70b140f..f8b2fd478 100644
--- a/config/locales/views/instructeurs/procedures/en.yml
+++ b/config/locales/views/instructeurs/procedures/en.yml
@@ -9,17 +9,6 @@ en:
archived: archived
dossiers_close_to_expiration: expiring
dossiers_supprimes_recemment: recently deleted
- dossiers_export:
- everything_csv_html: Ask an export in format .csv
(only folders, without repeatable fields)
- everything_xlsx_html: Ask an export in format .xlsx
- everything_ods_html: Ask an export in format .ods
- everything_zip_html: Ask an export in format .zip
- everything_short: Ask an export in format%{export_format}
- everything_pending_html: Ask an export in format %{export_format} is being generated
(ask %{export_time} ago)
- everything_ready_html: Download the export in format %{export_format}
(generated %{export_time} ago)
- download:
- one: Download a file
- other: Download %{count} files
email_usagers:
contact_users: Contact users (draft)
notice: "You will send a message to %{dossiers_count} whose files are in draft, in the instructor groups : %{groupe_instructeurs}."
diff --git a/config/locales/views/instructeurs/procedures/fr.yml b/config/locales/views/instructeurs/procedures/fr.yml
index 7d9f79ed1..8436728af 100644
--- a/config/locales/views/instructeurs/procedures/fr.yml
+++ b/config/locales/views/instructeurs/procedures/fr.yml
@@ -8,18 +8,7 @@ fr:
all: dossiers
archived: archivés
dossiers_close_to_expiration: expirant
- dossiers_supprimes_recemment: supprimés
- dossiers_export:
- everything_csv_html: Demander un export au format .csv
(uniquement les dossiers, sans les champs répétables)
- everything_xlsx_html: Demander un export au format .xlsx
- everything_ods_html: Demander un export au format .ods
- everything_zip_html: Demander un export au format .zip
- everything_short: Demander un export au format %{export_format}
- everything_pending_html: Un export au format %{export_format} est en train d’être généré
(demandé il y a %{export_time})
- everything_ready_html: Télécharger l’export au format %{export_format}
(généré il y a %{export_time})
- download:
- one: Télécharger un dossier
- other: Télécharger %{count} dossiers
+ dossiers_supprimes_recemment: supprimés
email_usagers:
contact_users: Contacter les usagers (brouillon)
notice: "Vous allez envoyer un message à %{dossiers_count} dont les dossiers sont en brouillon, dans les groupes instructeurs : %{groupe_instructeurs}."
diff --git a/config/routes.rb b/config/routes.rb
index 89a87b307..de17165e9 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -355,6 +355,7 @@ Rails.application.routes.draw do
post 'add_filter'
get 'remove_filter' => 'procedures#remove_filter', as: 'remove_filter'
get 'download_export'
+ post 'download_export'
get 'stats'
get 'email_notifications'
patch 'update_email_notifications'
diff --git a/spec/controllers/attachments_controller_spec.rb b/spec/controllers/attachments_controller_spec.rb
index fe10c5f03..8b1f8dff8 100644
--- a/spec/controllers/attachments_controller_spec.rb
+++ b/spec/controllers/attachments_controller_spec.rb
@@ -8,24 +8,24 @@ describe AttachmentsController, type: :controller do
describe '#show' do
render_views
- let(:format) { :js }
+ let(:format) { :turbo_stream }
subject do
request.headers['HTTP_REFERER'] = dossier_url(dossier)
- get :show, params: { id: attachment.id, signed_id: signed_id }, format: format, xhr: (format == :js)
+ get :show, params: { id: attachment.id, signed_id: signed_id }, format: format
end
context 'when authenticated' do
before { sign_in(user) }
- context 'when requesting Javascript' do
- let(:format) { :js }
+ context 'when requesting turbo_stream' do
+ let(:format) { :turbo_stream }
it { is_expected.to have_http_status(200) }
- it 'renders JS that replaces the attachment HTML' do
+ it 'renders turbo_stream that replaces the attachment HTML' do
subject
- expect(response.body).to have_text(".attachment-link[data-attachment-id=\"#{attachment.id}\"]")
+ expect(response.body).to include(ActionView::RecordIdentifier.dom_id(attachment, :show))
end
end
@@ -51,7 +51,7 @@ describe AttachmentsController, type: :controller do
let(:signed_id) { attachment.blob.signed_id }
subject do
- delete :destroy, params: { id: attachment.id, signed_id: signed_id }, format: :js
+ delete :destroy, params: { id: attachment.id, signed_id: signed_id }, format: :turbo_stream
end
context "when authenticated" do
diff --git a/spec/controllers/instructeurs/procedures_controller_spec.rb b/spec/controllers/instructeurs/procedures_controller_spec.rb
index 57e492fcb..dc1c31eaa 100644
--- a/spec/controllers/instructeurs/procedures_controller_spec.rb
+++ b/spec/controllers/instructeurs/procedures_controller_spec.rb
@@ -523,15 +523,15 @@ describe Instructeurs::ProceduresController, type: :controller do
end
end
- context 'when the js format is used' do
+ context 'when the turbo_stream format is used' do
before do
post :download_export,
params: { export_format: :csv, procedure_id: procedure.id },
- format: :js
+ format: :turbo_stream
end
it 'responds in the correct format' do
- expect(response.media_type).to eq('text/javascript')
+ expect(response.media_type).to eq('text/vnd.turbo-stream.html')
expect(response).to have_http_status(:ok)
end
end
diff --git a/spec/views/shared/attachment/_show.html.haml_spec.rb b/spec/views/shared/attachment/_show.html.haml_spec.rb
index b9737c8c4..6bd7b4586 100644
--- a/spec/views/shared/attachment/_show.html.haml_spec.rb
+++ b/spec/views/shared/attachment/_show.html.haml_spec.rb
@@ -6,7 +6,7 @@ describe 'shared/attachment/_show.html.haml', type: :view do
champ.piece_justificative_file.blob.update(metadata: champ.piece_justificative_file.blob.metadata.merge(virus_scan_result: virus_scan_result))
end
- subject { render 'shared/attachment/show', attachment: champ.piece_justificative_file.attachment }
+ subject { render Attachment::ShowComponent.new(attachment: champ.piece_justificative_file.attachment) }
context 'when there is no anti-virus scan' do
let(:virus_scan_result) { nil }
diff --git a/spec/views/shared/attachment/_update.html.haml_spec.rb b/spec/views/shared/attachment/_update.html.haml_spec.rb
index 6ec4d7aae..2430cf7cd 100644
--- a/spec/views/shared/attachment/_update.html.haml_spec.rb
+++ b/spec/views/shared/attachment/_update.html.haml_spec.rb
@@ -5,7 +5,7 @@ describe 'shared/attachment/_update.html.haml', type: :view do
subject do
form_for(champ.dossier) do |form|
- view.image_upload_and_render form, attached_file
+ view.render Attachment::EditComponent.image(form, attached_file)
end
end
@@ -53,12 +53,10 @@ describe 'shared/attachment/_update.html.haml', type: :view do
context 'when the user cannot destroy the attachment' do
subject do
form_for(champ.dossier) do |form|
- render 'shared/attachment/edit', {
- form: form,
+ render Attachment::EditComponent.new(form: form,
attached_file: attached_file,
accept: 'image/png',
- user_can_destroy: user_can_destroy
- }
+ user_can_destroy: user_can_destroy)
end
end