Merge pull request #7266 from tchak/refactor-poll-controller
turbo poll controller
This commit is contained in:
commit
185f2acdea
51 changed files with 421 additions and 217 deletions
92
app/components/attachment/edit_component.rb
Normal file
92
app/components/attachment/edit_component.rb
Normal file
|
@ -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
|
|
@ -0,0 +1,2 @@
|
||||||
|
---
|
||||||
|
en:
|
|
@ -0,0 +1,2 @@
|
||||||
|
---
|
||||||
|
fr:
|
|
@ -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)
|
27
app/components/attachment/show_component.rb
Normal file
27
app/components/attachment/show_component.rb
Normal file
|
@ -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
|
|
@ -0,0 +1,2 @@
|
||||||
|
---
|
||||||
|
en:
|
|
@ -0,0 +1,2 @@
|
||||||
|
---
|
||||||
|
fr:
|
|
@ -1,12 +1,5 @@
|
||||||
- should_display_link = (attachment.virus_scanner.safe? || !attachment.virus_scanner.started?) && !attachment.watermark_pending?
|
.attachment-link{ id: dom_id(attachment, :show) }
|
||||||
- user_can_upload = defined?(user_can_upload) ? user_can_upload : false
|
- if should_display_link?
|
||||||
- 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
|
|
||||||
= link_to url_for(attachment.blob), target: '_blank', rel: 'noopener', title: "Télécharger la pièce jointe" do
|
= link_to url_for(attachment.blob), target: '_blank', rel: 'noopener', title: "Télécharger la pièce jointe" do
|
||||||
%span.icon.attached
|
%span.icon.attached
|
||||||
= attachment.filename.to_s
|
= 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)
|
(ce fichier n’a pas été analysé par notre antivirus, téléchargez-le avec précaution)
|
||||||
|
|
||||||
- else
|
- else
|
||||||
|
%span{ data: poll_controller_options }
|
||||||
= attachment.filename.to_s
|
= attachment.filename.to_s
|
||||||
- if attachment.virus_scanner.pending?
|
- if attachment.virus_scanner.pending?
|
||||||
(analyse antivirus en cours
|
(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?
|
- elsif attachment.watermark_pending?
|
||||||
(traitement de la pièce en cours
|
(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?
|
- elsif attachment.virus_scanner.infected?
|
||||||
- if user_can_upload
|
- if user_can_upload?
|
||||||
(virus détecté, merci d’envoyer un autre fichier)
|
(virus détecté, merci d’envoyer un autre fichier)
|
||||||
- else
|
- else
|
||||||
(virus détecté, le téléchargement de ce fichier est bloqué)
|
(virus détecté, le téléchargement de ce fichier est bloqué)
|
||||||
- elsif attachment.virus_scanner.corrupt?
|
- elsif attachment.virus_scanner.corrupt?
|
||||||
- if user_can_upload
|
- if user_can_upload?
|
||||||
(le fichier est corrompu, merci d’envoyer un autre fichier)
|
(le fichier est corrompu, merci d’envoyer un autre fichier)
|
||||||
- else
|
- else
|
||||||
(le fichier est corrompu, le téléchargement est bloqué)
|
(le fichier est corrompu, le téléchargement est bloqué)
|
49
app/components/dossiers/export_component.rb
Normal file
49
app/components/dossiers/export_component.rb
Normal file
|
@ -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
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
en:
|
||||||
|
everything_csv_html: Ask an export in format .csv<br>(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<br>(ask %{export_time} ago)
|
||||||
|
everything_ready_html: Download the export in format %{export_format}<br>(generated %{export_time} ago)
|
||||||
|
download:
|
||||||
|
one: Download a file
|
||||||
|
other: Download %{count} files
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
everything_csv_html: Demander un export au format .csv<br>(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é<br>(demandé il y a %{export_time})
|
||||||
|
everything_ready_html: Télécharger l’export au format %{export_format}<br>(généré il y a %{export_time})
|
||||||
|
download:
|
||||||
|
one: Télécharger un dossier
|
||||||
|
other: Télécharger %{count} dossiers
|
|
@ -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)
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
- if commentaire.piece_jointe.attached?
|
- if commentaire.piece_jointe.attached?
|
||||||
.attachment-link
|
.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?
|
- if show_reply_button?
|
||||||
= button_tag type: 'button', class: 'button small message-answer-button', onclick: 'document.querySelector("#commentaire_body").focus()' do
|
= button_tag type: 'button', class: 'button small message-answer-button', onclick: 'document.querySelector("#commentaire_body").focus()' do
|
||||||
|
|
|
@ -7,15 +7,19 @@ class AttachmentsController < ApplicationController
|
||||||
@user_can_upload = params[:user_can_upload]
|
@user_can_upload = params[:user_can_upload]
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.js
|
format.turbo_stream
|
||||||
format.html { redirect_back(fallback_location: root_url) }
|
format.html { redirect_back(fallback_location: root_url) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
attachment = @blob.attachments.find(params[:id])
|
@attachment = @blob.attachments.find(params[:id])
|
||||||
@attachment_id = attachment.id
|
@attachment.purge_later
|
||||||
attachment.purge_later
|
flash.notice = 'La pièce jointe a bien été supprimée.'
|
||||||
flash.now.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
|
||||||
end
|
end
|
||||||
|
|
|
@ -156,7 +156,7 @@ module Instructeurs
|
||||||
|
|
||||||
if export.ready?
|
if export.ready?
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.js do
|
format.turbo_stream do
|
||||||
@procedure = procedure
|
@procedure = procedure
|
||||||
@statut = export_options[:statut]
|
@statut = export_options[:statut]
|
||||||
@dossiers_count = export.count
|
@dossiers_count = export.count
|
||||||
|
@ -172,7 +172,7 @@ module Instructeurs
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
notice_message = "Nous générons cet export. Veuillez revenir dans quelques minutes pour le télécharger."
|
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
|
@procedure = procedure
|
||||||
@statut = export_options[:statut]
|
@statut = export_options[:statut]
|
||||||
@dossiers_count = export.count
|
@dossiers_count = export.count
|
||||||
|
|
|
@ -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
|
|
|
@ -1,18 +1,20 @@
|
||||||
import { Application } from '@hotwired/stimulus';
|
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 { AutosaveController } from './autosave_controller';
|
||||||
import { AutosaveStatusController } from './autosave_status_controller';
|
import { AutosaveStatusController } from './autosave_status_controller';
|
||||||
|
import { GeoAreaController } from './geo_area_controller';
|
||||||
import { MenuButtonController } from './menu_button_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();
|
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('react', ReactController);
|
||||||
Stimulus.register('turbo-event', TurboEventController);
|
Stimulus.register('turbo-event', TurboEventController);
|
||||||
Stimulus.register('geo-area', GeoAreaController);
|
|
||||||
Stimulus.register('turbo-input', TurboInputController);
|
Stimulus.register('turbo-input', TurboInputController);
|
||||||
Stimulus.register('autosave', AutosaveController);
|
Stimulus.register('turbo-poll', TurboPollController);
|
||||||
Stimulus.register('autosave-status', AutosaveStatusController);
|
|
||||||
Stimulus.register('menu-button', MenuButtonController);
|
|
||||||
|
|
94
app/javascript/controllers/turbo_poll_controller.ts
Normal file
94
app/javascript/controllers/turbo_poll_controller.ts
Normal file
|
@ -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<string, PollState>();
|
|
@ -25,7 +25,7 @@
|
||||||
= tag[:description]
|
= tag[:description]
|
||||||
|
|
||||||
%h3.header-subsection Logo de l'attestation
|
%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
|
%p.notice
|
||||||
Formats acceptés : JPG / JPEG / PNG.
|
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.
|
Dimensions conseillées : au minimum 500 px de largeur ou de hauteur, poids maximum : 0,5 Mo.
|
||||||
|
|
||||||
%h3.header-subsection Tampon de l'attestation
|
%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
|
%p.notice
|
||||||
Formats acceptés : JPG / JPEG / PNG.
|
Formats acceptés : JPG / JPEG / PNG.
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
= f.select :zone_id, grouped_options_for_zone
|
= f.select :zone_id, grouped_options_for_zone
|
||||||
|
|
||||||
%h3.header-subsection Logo de la démarche
|
%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
|
%h3.header-subsection Conservation des données
|
||||||
= f.label :duree_conservation_dossiers_dans_ds do
|
= 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.text_field :cadre_juridique, class: 'form-control', placeholder: 'https://www.legifrance.gouv.fr/'
|
||||||
|
|
||||||
= f.label :deliberation, 'Importer le texte'
|
= f.label :deliberation, 'Importer le texte'
|
||||||
= text_upload_and_render f, @procedure.deliberation
|
= render Attachment::EditComponent.text(f, @procedure.deliberation)
|
||||||
|
|
||||||
%h3.header-subsection
|
%h3.header-subsection
|
||||||
RGPD
|
RGPD
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
%p.notice
|
%p.notice
|
||||||
Formats acceptés : .doc, .odt, .pdf, .ppt, .pptx
|
Formats acceptés : .doc, .odt, .pdf, .ppt, .pptx
|
||||||
- notice = @procedure.notice
|
- notice = @procedure.notice
|
||||||
= text_upload_and_render f, @procedure.notice
|
= render Attachment::EditComponent.text(f, @procedure.notice)
|
||||||
|
|
||||||
- if !@procedure.locked?
|
- if !@procedure.locked?
|
||||||
%h3.header-subsection À qui s’adresse ma démarche ?
|
%h3.header-subsection À qui s’adresse ma démarche ?
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<%= render_flash(timeout: 5000, sticky: true) %>
|
|
||||||
<%= remove_element(".attachment-actions-#{@attachment_id}") %>
|
|
||||||
<%= show_element(".attachment-input-#{@attachment_id}") %>
|
|
2
app/views/attachments/destroy.turbo_stream.haml
Normal file
2
app/views/attachments/destroy.turbo_stream.haml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
= turbo_stream.remove dom_id(@attachment, :actions)
|
||||||
|
= turbo_stream.show_all ".attachment-input-#{@attachment.id}"
|
|
@ -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 %>
|
|
2
app/views/attachments/show.turbo_stream.haml
Normal file
2
app/views/attachments/show.turbo_stream.haml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
= turbo_stream.replace dom_id(@attachment, :show) do
|
||||||
|
= render Attachment::ShowComponent.new(attachment: @attachment, user_can_upload: @user_can_upload)
|
|
@ -12,12 +12,12 @@
|
||||||
%p.introduction= @avis.introduction
|
%p.introduction= @avis.introduction
|
||||||
|
|
||||||
- if @avis.introduction_file.attached?
|
- 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/
|
%br/
|
||||||
|
|
||||||
= form_for @avis, url: expert_avis_path(@avis.procedure, @avis), html: { class: 'form', data: { persisted_content_id: @avis.id } } do |f|
|
= 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'
|
= 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
|
.flex.justify-between.align-baseline
|
||||||
%p.confidentiel.flex
|
%p.confidentiel.flex
|
||||||
|
|
|
@ -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
|
= 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
|
%p.tab-title Ajouter une pièce jointe
|
||||||
.form-group
|
.form-group
|
||||||
= text_upload_and_render f, avis.introduction_file
|
= render Attachment::EditComponent.text(f, avis.introduction_file)
|
||||||
|
|
||||||
- if linked_dossiers.present?
|
- if linked_dossiers.present?
|
||||||
= f.check_box :invite_linked_dossiers, {}, true, false
|
= f.check_box :invite_linked_dossiers, {}, true, false
|
||||||
|
|
|
@ -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'
|
= 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
|
%p.tab-title Ajouter une pièce jointe
|
||||||
.form-group
|
.form-group
|
||||||
= text_upload_and_render f, avis.introduction_file
|
= render Attachment::EditComponent.text(f, avis.introduction_file)
|
||||||
|
|
||||||
- if linked_dossiers.present?
|
- if linked_dossiers.present?
|
||||||
= f.check_box :invite_linked_dossiers, {}, true, false
|
= f.check_box :invite_linked_dossiers, {}, true, false
|
||||||
|
|
|
@ -33,6 +33,6 @@
|
||||||
%span.waiting
|
%span.waiting
|
||||||
= t('en_attente', scope: 'views.shared.avis')
|
= t('en_attente', scope: 'views.shared.avis')
|
||||||
- if avis.piece_justificative_file.attached?
|
- 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
|
.answer-body
|
||||||
= simple_format(avis.answer)
|
= simple_format(avis.answer)
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
%p.introduction= @avis.introduction
|
%p.introduction= @avis.introduction
|
||||||
|
|
||||||
- if @avis.introduction_file.attached?
|
- 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/
|
%br/
|
||||||
|
|
||||||
= form_for @avis, url: instructeur_avis_path(@avis.procedure, @avis), html: { class: 'form' } do |f|
|
= 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
|
= 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
|
.flex.justify-between.align-baseline
|
||||||
%p.confidentiel.flex
|
%p.confidentiel.flex
|
||||||
|
|
|
@ -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}")
|
|
|
@ -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 %>
|
|
|
@ -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)
|
|
@ -26,7 +26,7 @@
|
||||||
%p= message.body
|
%p= message.body
|
||||||
.answer.flex.align-start
|
.answer.flex.align-start
|
||||||
- if message.piece_jointe.present?
|
- 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
|
- else
|
||||||
.page-title.center
|
.page-title.center
|
||||||
%h2 Il n'y a aucun dossier en brouillon dans vos groupes instructeurs
|
%h2 Il n'y a aucun dossier en brouillon dans vos groupes instructeurs
|
||||||
|
|
|
@ -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 }
|
= 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
|
- if @dossiers_count > 0
|
||||||
.dossiers-export
|
.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
|
%table.table.dossiers-table.hoverable
|
||||||
%thead
|
%thead
|
||||||
|
|
|
@ -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"
|
= 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
|
%p.tab-title Ajouter une pièce jointe
|
||||||
.form-group
|
.form-group
|
||||||
= text_upload_and_render f, avis.introduction_file
|
= render Attachment::EditComponent.text(f, avis.introduction_file)
|
||||||
|
|
||||||
- if linked_dossiers.present?
|
- if linked_dossiers.present?
|
||||||
= f.check_box :invite_linked_dossiers, {}, true, false
|
= f.check_box :invite_linked_dossiers, {}, true, false
|
||||||
|
|
|
@ -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)
|
= 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?
|
- 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
|
.answer-body.mb-3
|
||||||
%p #{t('views.instructeurs.avis.introduction_file_explaination')} #{avis.claimant.email}
|
%p #{t('views.instructeurs.avis.introduction_file_explaination')} #{avis.claimant.email}
|
||||||
|
|
||||||
- if avis.piece_justificative_file.attached?
|
- 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
|
.answer-body
|
||||||
= simple_format(avis.answer)
|
= simple_format(avis.answer)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
- if flash.any?
|
- if flash.any?
|
||||||
= turbo_stream.replace 'flash_messages', partial: 'layouts/flash_messages'
|
= 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
|
- flash.clear
|
||||||
|
|
||||||
= yield
|
= yield
|
||||||
|
|
|
@ -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) }
|
|
|
@ -1,5 +1,5 @@
|
||||||
- pj = champ.piece_justificative_file
|
- pj = champ.piece_justificative_file
|
||||||
- if pj.attached?
|
- if pj.attached?
|
||||||
= render partial: "shared/attachment/show", locals: { attachment: pj.attachment }
|
= render Attachment::ShowComponent.new(attachment: pj.attachment)
|
||||||
- else
|
- else
|
||||||
Pièce justificative non fournie
|
Pièce justificative non fournie
|
||||||
|
|
|
@ -8,4 +8,4 @@
|
||||||
%td.libelle Justificatif :
|
%td.libelle Justificatif :
|
||||||
%td
|
%td
|
||||||
.action
|
.action
|
||||||
= render partial: 'shared/attachment/show', locals: { attachment: dossier.justificatif_motivation.attachment }
|
= render Attachment::ShowComponent.new(attachment: dossier.justificatif_motivation.attachment)
|
||||||
|
|
|
@ -1,4 +1 @@
|
||||||
= render 'shared/attachment/edit',
|
= render Attachment::EditComponent.new(form: form, attached_file: champ.piece_justificative_file, template: champ.type_de_champ.piece_justificative_template, user_can_destroy: true)
|
||||||
{ form: form,
|
|
||||||
attached_file: champ.piece_justificative_file,
|
|
||||||
template: champ.type_de_champ.piece_justificative_template, user_can_destroy: true }
|
|
||||||
|
|
|
@ -1,4 +1 @@
|
||||||
= render 'shared/attachment/edit',
|
= render Attachment::EditComponent.new(form: form, attached_file: champ.piece_justificative_file, user_can_destroy: true)
|
||||||
{ form: form,
|
|
||||||
attached_file: champ.piece_justificative_file,
|
|
||||||
user_can_destroy: true }
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
- if dossier.present? && dossier.justificatif_motivation.attached?
|
- 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)
|
||||||
|
|
|
@ -87,5 +87,8 @@ module TPS
|
||||||
config.view_component.show_previews_source = true
|
config.view_component.show_previews_source = true
|
||||||
config.view_component.default_preview_layout = 'component_preview'
|
config.view_component.default_preview_layout = 'component_preview'
|
||||||
config.view_component.preview_paths << "#{Rails.root}/spec/components/previews"
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,17 +9,6 @@ en:
|
||||||
archived: archived
|
archived: archived
|
||||||
dossiers_close_to_expiration: expiring
|
dossiers_close_to_expiration: expiring
|
||||||
dossiers_supprimes_recemment: recently deleted
|
dossiers_supprimes_recemment: recently deleted
|
||||||
dossiers_export:
|
|
||||||
everything_csv_html: Ask an export in format .csv<br>(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<br>(ask %{export_time} ago)
|
|
||||||
everything_ready_html: Download the export in format %{export_format}<br>(generated %{export_time} ago)
|
|
||||||
download:
|
|
||||||
one: Download a file
|
|
||||||
other: Download %{count} files
|
|
||||||
email_usagers:
|
email_usagers:
|
||||||
contact_users: Contact users (draft)
|
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}."
|
notice: "You will send a message to %{dossiers_count} whose files are in draft, in the instructor groups : %{groupe_instructeurs}."
|
||||||
|
|
|
@ -8,18 +8,7 @@ fr:
|
||||||
all: dossiers
|
all: dossiers
|
||||||
archived: archivés
|
archived: archivés
|
||||||
dossiers_close_to_expiration: expirant
|
dossiers_close_to_expiration: expirant
|
||||||
dossiers_supprimes_recemment: supprimés
|
dossiers_supprimes_recemment: supprimés
|
||||||
dossiers_export:
|
|
||||||
everything_csv_html: Demander un export au format .csv<br>(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é<br>(demandé il y a %{export_time})
|
|
||||||
everything_ready_html: Télécharger l’export au format %{export_format}<br>(généré il y a %{export_time})
|
|
||||||
download:
|
|
||||||
one: Télécharger un dossier
|
|
||||||
other: Télécharger %{count} dossiers
|
|
||||||
email_usagers:
|
email_usagers:
|
||||||
contact_users: Contacter les usagers (brouillon)
|
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}."
|
notice: "Vous allez envoyer un message à %{dossiers_count} dont les dossiers sont en brouillon, dans les groupes instructeurs : %{groupe_instructeurs}."
|
||||||
|
|
|
@ -355,6 +355,7 @@ Rails.application.routes.draw do
|
||||||
post 'add_filter'
|
post 'add_filter'
|
||||||
get 'remove_filter' => 'procedures#remove_filter', as: 'remove_filter'
|
get 'remove_filter' => 'procedures#remove_filter', as: 'remove_filter'
|
||||||
get 'download_export'
|
get 'download_export'
|
||||||
|
post 'download_export'
|
||||||
get 'stats'
|
get 'stats'
|
||||||
get 'email_notifications'
|
get 'email_notifications'
|
||||||
patch 'update_email_notifications'
|
patch 'update_email_notifications'
|
||||||
|
|
|
@ -8,24 +8,24 @@ describe AttachmentsController, type: :controller do
|
||||||
describe '#show' do
|
describe '#show' do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
let(:format) { :js }
|
let(:format) { :turbo_stream }
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
request.headers['HTTP_REFERER'] = dossier_url(dossier)
|
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
|
end
|
||||||
|
|
||||||
context 'when authenticated' do
|
context 'when authenticated' do
|
||||||
before { sign_in(user) }
|
before { sign_in(user) }
|
||||||
|
|
||||||
context 'when requesting Javascript' do
|
context 'when requesting turbo_stream' do
|
||||||
let(:format) { :js }
|
let(:format) { :turbo_stream }
|
||||||
|
|
||||||
it { is_expected.to have_http_status(200) }
|
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
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ describe AttachmentsController, type: :controller do
|
||||||
let(:signed_id) { attachment.blob.signed_id }
|
let(:signed_id) { attachment.blob.signed_id }
|
||||||
|
|
||||||
subject do
|
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
|
end
|
||||||
|
|
||||||
context "when authenticated" do
|
context "when authenticated" do
|
||||||
|
|
|
@ -523,15 +523,15 @@ describe Instructeurs::ProceduresController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the js format is used' do
|
context 'when the turbo_stream format is used' do
|
||||||
before do
|
before do
|
||||||
post :download_export,
|
post :download_export,
|
||||||
params: { export_format: :csv, procedure_id: procedure.id },
|
params: { export_format: :csv, procedure_id: procedure.id },
|
||||||
format: :js
|
format: :turbo_stream
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'responds in the correct format' do
|
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)
|
expect(response).to have_http_status(:ok)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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))
|
champ.piece_justificative_file.blob.update(metadata: champ.piece_justificative_file.blob.metadata.merge(virus_scan_result: virus_scan_result))
|
||||||
end
|
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
|
context 'when there is no anti-virus scan' do
|
||||||
let(:virus_scan_result) { nil }
|
let(:virus_scan_result) { nil }
|
||||||
|
|
|
@ -5,7 +5,7 @@ describe 'shared/attachment/_update.html.haml', type: :view do
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
form_for(champ.dossier) do |form|
|
form_for(champ.dossier) do |form|
|
||||||
view.image_upload_and_render form, attached_file
|
view.render Attachment::EditComponent.image(form, attached_file)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -53,12 +53,10 @@ describe 'shared/attachment/_update.html.haml', type: :view do
|
||||||
context 'when the user cannot destroy the attachment' do
|
context 'when the user cannot destroy the attachment' do
|
||||||
subject do
|
subject do
|
||||||
form_for(champ.dossier) do |form|
|
form_for(champ.dossier) do |form|
|
||||||
render 'shared/attachment/edit', {
|
render Attachment::EditComponent.new(form: form,
|
||||||
form: form,
|
|
||||||
attached_file: attached_file,
|
attached_file: attached_file,
|
||||||
accept: 'image/png',
|
accept: 'image/png',
|
||||||
user_can_destroy: user_can_destroy
|
user_can_destroy: user_can_destroy)
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue