Merge branch 'main' into feature/prefill_repetible
This commit is contained in:
parent
f91cc05d95
commit
d7b01255fe
82 changed files with 764 additions and 563 deletions
|
@ -635,7 +635,7 @@ GEM
|
|||
nokogiri (>= 1.6.2)
|
||||
rexml
|
||||
xmlenc (>= 0.7.1)
|
||||
sanitize (6.0.0)
|
||||
sanitize (6.0.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
sanitize-url (0.1.4)
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
// The procedure description can still be read from the /commencer
|
||||
// pages.
|
||||
@media (max-width: $two-columns-breakpoint) {
|
||||
.procedure-preview,
|
||||
.agent-intro {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,14 @@ $contact-padding: $default-space * 2;
|
|||
padding-bottom: $contact-padding;
|
||||
}
|
||||
|
||||
.recommandations {
|
||||
p {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-bottom: $default-space;
|
||||
}
|
||||
|
|
|
@ -163,6 +163,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.drop_down_other { // scss-lint:disable SelectorFormat
|
||||
label {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=text],
|
||||
input[type=email],
|
||||
input[type=password],
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown-export .dropdown-content {
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
.print-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
|
|
|
@ -18,3 +18,9 @@
|
|||
width: 9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.fr-footer__top-link p {
|
||||
margin-bottom: 0;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ $procedure-description-line-height: 22px;
|
|||
}
|
||||
|
||||
.simple {
|
||||
font-size: 24px;
|
||||
margin-bottom: 0.2rem;
|
||||
font-size: 1.5rem;
|
||||
color: $blue-france-500;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -143,6 +144,14 @@ $procedure-description-line-height: 22px;
|
|||
}
|
||||
}
|
||||
|
||||
.no-procedure-presentation {
|
||||
margin-bottom: 1.6rem;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.procedure-context-content {
|
||||
@media (max-width: $procedure-context-breakpoint) {
|
||||
input[type=submit] {
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
%span.dropdown{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.fr-btn--sm.dropdown-button{ data: { menu_button_target: 'button' }, class: @class_btn.present? ? @class_btn : 'fr-btn--secondary' }
|
||||
- if @count.nil?
|
||||
= t(".download_all")
|
||||
- else
|
||||
= t(".download", count: @count)
|
||||
.dropdown-content.fade-in-down{ style: 'width: 450px', data: { menu_button_target: 'menu' }, id: @count.nil? ? "download_menu" : "download_all_menu" }
|
||||
%ul.dropdown-items{ 'data-turbo': 'true' }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :span, button_options: { class: ['fr-btn--sm', @class_btn.present? ? @class_btn : 'fr-btn--secondary']}, menu_options: { id: @count.nil? ? "download_menu" : "download_all_menu", class: ['dropdown-export'] }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= @count.nil? ? t(".download_all") : t(".download", count: @count)
|
||||
- exports.each do |item|
|
||||
- export = item[:export]
|
||||
%li
|
||||
|
||||
- if export.nil?
|
||||
= link_to t(".everything_#{item[:format]}_html"), download_export_path(export_format: item[:format]), data: { turbo_method: :post }
|
||||
- menu.with_item do
|
||||
= link_to download_export_path(export_format: item[:format]), role: 'menuitem', data: { turbo_method: :post, turbo: true } do
|
||||
= t(".everything_#{item[:format]}_html")
|
||||
- elsif export.available?
|
||||
= link_to ready_link_label(export), export.file.service_url, target: "_blank", rel: "noopener"
|
||||
- menu.with_item do
|
||||
%div
|
||||
= link_to ready_link_label(export), export.file.service_url, target: "_blank", rel: "noopener", role: 'menuitem'
|
||||
- if export.old?
|
||||
= button_to download_export_path(export_format: export.format, force_export: true), **refresh_button_options(export) do
|
||||
= button_to download_export_path(export_format: export.format, force_export: true), refresh_button_options(export).merge(role: 'menuitem') do
|
||||
.icon.retry
|
||||
- else
|
||||
- menu.with_item(aria: {disabled:"true"}, class: 'selected') do
|
||||
%span{ data: poll_controller_options(export) }
|
||||
= pending_label(export)
|
||||
|
|
50
app/components/dropdown/menu_component.rb
Normal file
50
app/components/dropdown/menu_component.rb
Normal file
|
@ -0,0 +1,50 @@
|
|||
class Dropdown::MenuComponent < ApplicationComponent
|
||||
renders_one :button_inner_html
|
||||
# beware, items elements like button_to/link_to must include role: 'menuitem' for aria reason
|
||||
renders_many :items, -> (options = {}, &block) do
|
||||
tag.li(**options.merge(role: 'none'), &block)
|
||||
end
|
||||
renders_many :forms
|
||||
|
||||
def initialize(wrapper:,
|
||||
wrapper_options: {},
|
||||
button_options: {},
|
||||
menu_options: {})
|
||||
@wrapper = wrapper
|
||||
@wrapper_options = wrapper_options
|
||||
@button_options = button_options
|
||||
@menu_options = menu_options
|
||||
end
|
||||
|
||||
def wrapper_options
|
||||
@wrapper_options.deep_merge({
|
||||
class: wrapper_class_names,
|
||||
data: { controller: 'menu-button' }
|
||||
})
|
||||
end
|
||||
|
||||
def wrapper_class_names
|
||||
['dropdown'] + Array(@wrapper_options[:class])
|
||||
end
|
||||
|
||||
def button_id
|
||||
"#{menu_id}_button"
|
||||
end
|
||||
|
||||
def menu_id
|
||||
@menu_options[:id] ||= SecureRandom.uuid
|
||||
@menu_options[:id]
|
||||
end
|
||||
|
||||
def menu_role
|
||||
forms? ? :region : :menu
|
||||
end
|
||||
|
||||
def menu_class_names
|
||||
['dropdown-content'] + Array(@menu_options[:class])
|
||||
end
|
||||
|
||||
def button_class_names
|
||||
['fr-btn', 'dropdown-button'] + Array(@button_options[:class])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
= content_tag(@wrapper, wrapper_options) do
|
||||
%button{ class: button_class_names, id: button_id, data: { menu_button_target: 'button' }, "aria-expanded": "false", 'aria-haspopup': 'true', 'aria-controls': menu_id }
|
||||
= button_inner_html
|
||||
|
||||
%div{ data: { menu_button_target: 'menu' }, id: menu_id, 'aria-labelledby': button_id, role: menu_role, 'tab-index': -1, class: menu_class_names }
|
||||
|
||||
-# the dropdown can be a menu with a list of item
|
||||
- if items?
|
||||
%ul.dropdown-items.fr-pl-0{ role: 'none' }
|
||||
- items.each do |dropdown_item|
|
||||
= dropdown_item
|
||||
-# the dropdown can be a menu with forms
|
||||
- if forms?
|
||||
- forms.each do |form|
|
||||
= form
|
|
@ -1,4 +1,4 @@
|
|||
.drop_down_other{ class: @champ.other_value_present? ? '' : 'hidden' }
|
||||
.notice
|
||||
%p Veuillez saisir votre autre choix
|
||||
= @form.text_field :value_other, maxlength: 200, size: nil, disabled: !@champ.other_value_present?
|
||||
%label{ for: dom_id(@champ, :value_other) } Veuillez saisir votre autre choix
|
||||
= @form.text_field :value_other, maxlength: 200, size: nil, id: dom_id(@champ, :value_other), disabled: !@champ.other_value_present?
|
||||
|
|
|
@ -8,6 +8,7 @@ module Administrateurs
|
|||
|
||||
def edit
|
||||
@attestation_template = build_attestation_template
|
||||
@attestation_template.validate
|
||||
end
|
||||
|
||||
def update
|
||||
|
|
|
@ -140,7 +140,7 @@ module Experts
|
|||
end
|
||||
|
||||
def telecharger_pjs
|
||||
files = ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: @dossier.id), true)
|
||||
files = ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: @dossier.id))
|
||||
cleaned_files = ActiveStorage::DownloadableFile.cleanup_list_from_dossier(files)
|
||||
|
||||
zipline(cleaned_files, "dossier-#{@dossier.id}.zip")
|
||||
|
|
|
@ -235,7 +235,7 @@ module Instructeurs
|
|||
end
|
||||
|
||||
def telecharger_pjs
|
||||
files = ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id), true)
|
||||
files = ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id), with_champs_private: true, include_infos_administration: true)
|
||||
cleaned_files = ActiveStorage::DownloadableFile.cleanup_list_from_dossier(files)
|
||||
|
||||
zipline(cleaned_files, "dossier-#{dossier.id}.zip")
|
||||
|
|
|
@ -26,11 +26,7 @@ module Users
|
|||
@dossiers_invites = current_user.dossiers_invites.merge(dossiers_visibles)
|
||||
@dossiers_supprimes_recemment = current_user.dossiers.hidden_by_user.merge(dossiers)
|
||||
@dossiers_supprimes_definitivement = current_user.deleted_dossiers.order_by_updated_at.page(page)
|
||||
@dossier_transfers = DossierTransfer
|
||||
.includes(dossiers: :user)
|
||||
.with_dossiers
|
||||
.where(email: current_user.email)
|
||||
.page(page)
|
||||
@dossier_transfers = DossierTransfer.for_email(current_user.email).page(page)
|
||||
@statut = statut(@user_dossiers, @dossiers_traites, @dossiers_invites, @dossiers_supprimes_recemment, @dossiers_supprimes_definitivement, @dossier_transfers, @dossiers_close_to_expiration, params[:statut])
|
||||
end
|
||||
|
||||
|
|
|
@ -17,8 +17,11 @@ export function useDeferredSubmit(input?: HTMLInputElement): {
|
|||
runCallback();
|
||||
|
||||
if (
|
||||
!Array.from(form.elements).some((e) =>
|
||||
e.hasAttribute('data-direct-upload-url')
|
||||
!Array.from(form.elements).some(
|
||||
(e) =>
|
||||
e.hasAttribute('data-direct-upload-url') &&
|
||||
'value' in e &&
|
||||
e.value != ''
|
||||
)
|
||||
) {
|
||||
form.submit();
|
||||
|
|
|
@ -65,7 +65,10 @@ export class ApplicationController extends Controller {
|
|||
FOCUS_EVENTS.includes(targetOrEventName)
|
||||
);
|
||||
} else {
|
||||
invariant(eventNameOrHandler == 'string', 'event name is required');
|
||||
invariant(
|
||||
typeof eventNameOrHandler == 'string',
|
||||
'event name is required'
|
||||
);
|
||||
invariant(handler, 'handler is required');
|
||||
this.onTarget(targetOrEventName, eventNameOrHandler, handler);
|
||||
}
|
||||
|
|
|
@ -89,9 +89,12 @@ export class AutosaveController extends ApplicationController {
|
|||
isCheckboxOrRadioInputElement(target) ||
|
||||
(!this.saveOnInput && isTextInputElement(target))
|
||||
) {
|
||||
// Wait next tick so champs having JS can interact
|
||||
// with form elements before extracting form data.
|
||||
setTimeout(() => {
|
||||
this.enqueueAutosaveRequest();
|
||||
|
||||
this.showConditionnalSpinner(target);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ export class ChampDropdownController extends ApplicationController {
|
|||
if (target.value == '__other__') {
|
||||
show(inputGroup);
|
||||
input.disabled = false;
|
||||
input.focus();
|
||||
} else {
|
||||
hide(inputGroup);
|
||||
input.disabled = true;
|
||||
|
|
|
@ -6,53 +6,26 @@ export class MenuButtonController extends ApplicationController {
|
|||
declare readonly buttonTarget: HTMLButtonElement;
|
||||
declare readonly menuTarget: HTMLElement;
|
||||
|
||||
#teardown?: () => void;
|
||||
|
||||
connect() {
|
||||
this.setup();
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
this.#teardown?.();
|
||||
}
|
||||
|
||||
private get isOpen() {
|
||||
return (this.element as HTMLElement).classList.contains('open');
|
||||
}
|
||||
|
||||
private get isMenu() {
|
||||
return !(this.element as HTMLElement).dataset.popover;
|
||||
return this.menuTarget.getAttribute('role') == 'menu';
|
||||
}
|
||||
|
||||
private setup() {
|
||||
this.buttonTarget.setAttribute(
|
||||
'aria-haspopup',
|
||||
this.isMenu ? 'menu' : 'true'
|
||||
);
|
||||
this.buttonTarget.setAttribute('aria-controls', this.menuTarget.id);
|
||||
if (!this.buttonTarget.id) {
|
||||
this.buttonTarget.id = `${this.menuTarget.id}_button`;
|
||||
}
|
||||
|
||||
this.menuTarget.setAttribute('aria-labelledby', this.buttonTarget.id);
|
||||
this.menuTarget.setAttribute('role', this.isMenu ? 'menu' : 'region');
|
||||
// see:
|
||||
// To progressively enhance this navigation widget that is by default accessible,
|
||||
// the class to hide the menu and the inclusion of tabindex="-1" on the interactive menuitem
|
||||
// content should be added with JavaScript on load.
|
||||
this.menuTarget.classList.add('fade-in-down');
|
||||
this.menuTarget.setAttribute('tab-index', '-1');
|
||||
|
||||
if (this.isMenu) {
|
||||
for (const menuItem of this.menuTarget.querySelectorAll('a')) {
|
||||
menuItem.setAttribute('role', 'menuitem');
|
||||
}
|
||||
for (const dropdownItems of this.menuTarget.querySelectorAll(
|
||||
'.dropdown-items'
|
||||
)) {
|
||||
dropdownItems.setAttribute('role', 'none');
|
||||
}
|
||||
for (const dropdownItems of this.menuTarget.querySelectorAll(
|
||||
'.dropdown-items > li'
|
||||
)) {
|
||||
dropdownItems.setAttribute('role', 'none');
|
||||
}
|
||||
this.menuItems.map((menuItem) => menuItem.setAttribute('tabindex', '-1'));
|
||||
}
|
||||
|
||||
this.on('click', (event) => {
|
||||
|
@ -78,6 +51,14 @@ export class MenuButtonController extends ApplicationController {
|
|||
this.onMenuKeydown(event);
|
||||
}
|
||||
});
|
||||
|
||||
this.on(document.body, 'click', (event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
if (this.isOpen && this.isClickOutside(target)) {
|
||||
this.menuTarget.classList.remove('fade-in-down');
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private open(focusMenuItem: 'first' | 'last' = 'first') {
|
||||
|
@ -85,30 +66,18 @@ export class MenuButtonController extends ApplicationController {
|
|||
this.menuTarget.parentElement?.classList.add('open');
|
||||
this.menuTarget.focus();
|
||||
|
||||
const onClickBody = (event: Event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
if (this.isClickOutside(target)) {
|
||||
this.menuTarget.classList.remove('fade-in-down');
|
||||
this.close();
|
||||
}
|
||||
};
|
||||
requestAnimationFrame(() => {
|
||||
if (focusMenuItem == 'first') {
|
||||
this.setFocusToFirstMenuitem();
|
||||
} else {
|
||||
this.setFocusToLastMenuitem();
|
||||
}
|
||||
document.body.addEventListener('click', onClickBody);
|
||||
});
|
||||
|
||||
this.#teardown = () =>
|
||||
document.body.removeEventListener('click', onClickBody);
|
||||
}
|
||||
|
||||
private close() {
|
||||
this.buttonTarget.removeAttribute('aria-expanded');
|
||||
this.buttonTarget.setAttribute('aria-expanded', 'false');
|
||||
this.menuTarget.parentElement?.classList.remove('open');
|
||||
this.#teardown?.();
|
||||
this.setFocusToMenuitem(null);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class ActiveStorage::DownloadableFile
|
||||
def self.create_list_from_dossiers(dossiers, for_expert = false)
|
||||
PiecesJustificativesService.generate_dossier_export(dossiers, include_infos_administration: !for_expert) +
|
||||
PiecesJustificativesService.liste_documents(dossiers, for_expert)
|
||||
def self.create_list_from_dossiers(dossiers, with_bills: false, with_champs_private: false, include_infos_administration: false)
|
||||
PiecesJustificativesService.generate_dossier_export(dossiers, include_infos_administration:) +
|
||||
PiecesJustificativesService.liste_documents(dossiers, with_bills:, with_champs_private:)
|
||||
end
|
||||
|
||||
def self.cleanup_list_from_dossier(files)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
# confidentiel :boolean default(FALSE), not null
|
||||
# email :string
|
||||
# introduction :text
|
||||
# reminded_at :datetime
|
||||
# revoked_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
|
|
|
@ -226,7 +226,7 @@ class Champ < ApplicationRecord
|
|||
private
|
||||
|
||||
def html_id
|
||||
"#{stable_id}-#{id}"
|
||||
"champ-#{stable_id}-#{id}"
|
||||
end
|
||||
|
||||
def needs_dossier_id?
|
||||
|
@ -238,7 +238,7 @@ class Champ < ApplicationRecord
|
|||
end
|
||||
|
||||
def cleanup_if_empty
|
||||
if external_id_changed?
|
||||
if persisted? && external_id_changed?
|
||||
self.data = nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,7 +39,7 @@ class Champs::DateChamp < Champ
|
|||
private
|
||||
|
||||
def convert_to_iso8601
|
||||
return if valid_iso8601?
|
||||
return if likely_iso8601_format? && parsable_iso8601?
|
||||
|
||||
self.value = if /^\d{2}\/\d{2}\/\d{4}$/.match?(value)
|
||||
Date.parse(value).iso8601
|
||||
|
@ -49,12 +49,20 @@ class Champs::DateChamp < Champ
|
|||
end
|
||||
|
||||
def iso_8601
|
||||
return if valid_iso8601? || value.blank?
|
||||
return if parsable_iso8601? || value.blank?
|
||||
# i18n-tasks-use t('errors.messages.not_a_date')
|
||||
errors.add :date, errors.generate_message(:value, :not_a_date)
|
||||
end
|
||||
|
||||
def valid_iso8601?
|
||||
def likely_iso8601_format?
|
||||
/^\d{4}-\d{2}-\d{2}$/.match?(value)
|
||||
end
|
||||
|
||||
def parsable_iso8601?
|
||||
Date.parse(value)
|
||||
true
|
||||
rescue ArgumentError, # case 2023-27-02, out of range
|
||||
TypeError # nil
|
||||
false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,32 +54,32 @@ module DossierRebaseConcern
|
|||
.group_by(&:op)
|
||||
.tap { _1.default = [] }
|
||||
|
||||
champs_by_stable_id = champs
|
||||
.joins(:type_de_champ)
|
||||
.group_by(&:stable_id)
|
||||
.transform_values { Champ.where(id: _1) }
|
||||
|
||||
# add champ
|
||||
changes_by_op[:add]
|
||||
.map(&:stable_id)
|
||||
.map { target_coordinates_by_stable_id[_1] }
|
||||
.each { add_new_champs_for_revision(_1) }
|
||||
.each { add_new_champs_for_revision(target_coordinates_by_stable_id[_1.stable_id]) }
|
||||
|
||||
# remove champ
|
||||
changes_by_op[:remove]
|
||||
.each { delete_champs_for_revision(_1.stable_id) }
|
||||
.each { champs_by_stable_id[_1.stable_id].destroy_all }
|
||||
|
||||
if brouillon?
|
||||
changes_by_op[:update]
|
||||
.map { |change| [change, champs.joins(:type_de_champ).where(type_de_champ: { stable_id: change.stable_id })] }
|
||||
.each { |change, champs| apply(change, champs) }
|
||||
.each { apply(_1, champs_by_stable_id[_1.stable_id]) }
|
||||
end
|
||||
|
||||
# due to repetition tdc clone on update or erase
|
||||
# we must reassign tdc to the latest version
|
||||
Champ
|
||||
.includes(:type_de_champ)
|
||||
.where(dossier: self)
|
||||
.map { [_1, target_coordinates_by_stable_id[_1.stable_id].type_de_champ] }
|
||||
.each { |champ, target_tdc| champ.update_columns(type_de_champ_id: target_tdc.id, rebased_at: Time.zone.now) }
|
||||
champs_by_stable_id
|
||||
.filter_map { |stable_id, champs| [target_coordinates_by_stable_id[stable_id].type_de_champ_id, champs] if champs.present? }
|
||||
.each { |type_de_champ_id, champs| champs.update_all(type_de_champ_id:) }
|
||||
|
||||
# update dossier revision
|
||||
self.update_column(:revision_id, target_revision.id)
|
||||
update_column(:revision_id, target_revision.id)
|
||||
end
|
||||
|
||||
def apply(change, champs)
|
||||
|
@ -92,19 +92,28 @@ module DossierRebaseConcern
|
|||
value: nil,
|
||||
value_json: nil,
|
||||
external_id: nil,
|
||||
data: nil)
|
||||
data: nil,
|
||||
rebased_at: Time.zone.now)
|
||||
when :drop_down_options
|
||||
# we are removing options, we need to remove the value if it contains one of the removed options
|
||||
removed_options = change.from - change.to
|
||||
if removed_options.present? && champs.any? { _1.in?(removed_options) }
|
||||
champs.filter { _1.in?(removed_options) }.each { _1.remove_option(removed_options) }
|
||||
champs.filter { _1.in?(removed_options) }.each do
|
||||
_1.remove_option(removed_options)
|
||||
_1.update_column(:rebased_at, Time.zone.now)
|
||||
end
|
||||
end
|
||||
when :carte_layers
|
||||
# if we are removing cadastres layer, we need to remove cadastre geo areas
|
||||
if change.from.include?(:cadastres) && !change.to.include?(:cadastres)
|
||||
champs.each { _1.cadastres.each(&:destroy) }
|
||||
champs.filter { _1.cadastres.present? }.each do
|
||||
_1.cadastres.each(&:destroy)
|
||||
_1.update_column(:rebased_at, Time.zone.now)
|
||||
end
|
||||
end
|
||||
else
|
||||
champs.update_all(rebased_at: Time.zone.now)
|
||||
end
|
||||
end
|
||||
|
||||
def add_new_champs_for_revision(target_coordinate)
|
||||
|
@ -126,20 +135,13 @@ module DossierRebaseConcern
|
|||
end
|
||||
|
||||
def create_champ(target_coordinate, parent, row_id: nil)
|
||||
params = { revision: target_coordinate.revision, row_id: }.compact
|
||||
params = { revision: target_coordinate.revision, rebased_at: Time.zone.now, row_id: }.compact
|
||||
champ = target_coordinate
|
||||
.type_de_champ
|
||||
.build_champ(params)
|
||||
parent.champs << champ
|
||||
end
|
||||
|
||||
def delete_champs_for_revision(stable_id)
|
||||
champs
|
||||
.joins(:type_de_champ)
|
||||
.where(types_de_champ: { stable_id: })
|
||||
.destroy_all
|
||||
end
|
||||
|
||||
def purge_piece_justificative_file(champ)
|
||||
ActiveStorage::Attachment.where(id: champ.piece_justificative_file.ids).delete_all
|
||||
end
|
||||
|
|
|
@ -1184,7 +1184,7 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
|
||||
def geo_data?
|
||||
geo_areas.present?
|
||||
GeoArea.exists?(champ_id: champs_public.ids + champs_private.ids)
|
||||
end
|
||||
|
||||
def to_feature_collection
|
||||
|
|
|
@ -8,15 +8,18 @@
|
|||
# updated_at :datetime not null
|
||||
#
|
||||
class DossierTransfer < ApplicationRecord
|
||||
include EmailSanitizableConcern
|
||||
has_many :dossiers, dependent: :nullify
|
||||
|
||||
EXPIRATION_LIMIT = 2.weeks
|
||||
|
||||
validates :email, format: { with: Devise.email_regexp }
|
||||
before_validation -> { sanitize_email(:email) }
|
||||
|
||||
scope :pending, -> { where('created_at > ?', (Time.zone.now - EXPIRATION_LIMIT)) }
|
||||
scope :stale, -> { where('created_at < ?', (Time.zone.now - EXPIRATION_LIMIT)) }
|
||||
scope :with_dossiers, -> { joins(:dossiers).merge(Dossier.visible_by_user) }
|
||||
scope :for_email, -> (email) { includes(dossiers: :user).with_dossiers.where(email: email) }
|
||||
|
||||
after_create_commit :send_notification
|
||||
|
||||
|
|
|
@ -330,8 +330,11 @@ class ProcedurePresentation < ApplicationRecord
|
|||
if field['scope'].present?
|
||||
I18n.t(field['scope']).map(&:to_a).map(&:reverse)
|
||||
elsif field['table'] == 'groupe_instructeur'
|
||||
instructeur.groupe_instructeurs
|
||||
.map { [_1.label, _1.id] }
|
||||
instructeur.groupe_instructeurs.filter_map do
|
||||
if _1.procedure_id == procedure.id
|
||||
[_1.label, _1.id]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -243,7 +243,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
end
|
||||
|
||||
def only_present_on_draft?
|
||||
revisions.size == 1
|
||||
revisions.one? && revisions.first.draft?
|
||||
end
|
||||
|
||||
def drop_down_other?
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
class PiecesJustificativesService
|
||||
def self.liste_documents(dossiers, for_expert)
|
||||
def self.liste_documents(dossiers, with_bills:, with_champs_private:)
|
||||
bill_ids = []
|
||||
|
||||
docs = dossiers.in_batches.flat_map do |batch|
|
||||
pjs = pjs_for_champs(batch, for_expert) +
|
||||
pjs = pjs_for_champs(batch, with_champs_private:) +
|
||||
pjs_for_commentaires(batch) +
|
||||
pjs_for_dossier(batch)
|
||||
|
||||
if !for_expert
|
||||
if with_bills
|
||||
# some bills are shared among operations
|
||||
# so first, all the bill_ids are fetched
|
||||
operation_logs, some_bill_ids = operation_logs_and_signature_ids(batch)
|
||||
|
@ -19,7 +19,7 @@ class PiecesJustificativesService
|
|||
pjs
|
||||
end
|
||||
|
||||
if !for_expert
|
||||
if with_bills
|
||||
# then the bills are retrieved without duplication
|
||||
docs += signatures(bill_ids.uniq)
|
||||
end
|
||||
|
@ -117,12 +117,12 @@ class PiecesJustificativesService
|
|||
|
||||
private
|
||||
|
||||
def self.pjs_for_champs(dossiers, for_expert = false)
|
||||
def self.pjs_for_champs(dossiers, with_champs_private:)
|
||||
champs = Champ
|
||||
.joins(:piece_justificative_file_attachments)
|
||||
.where(type: "Champs::PieceJustificativeChamp", dossier: dossiers)
|
||||
|
||||
if for_expert
|
||||
if !with_champs_private
|
||||
champs = champs.where(private: false)
|
||||
end
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class ProcedureArchiveService
|
|||
dossiers.processed_in_month(archive.month)
|
||||
end
|
||||
|
||||
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers)
|
||||
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers, with_bills: true, with_champs_private: true)
|
||||
|
||||
DownloadableFileService.download_and_zip(@procedure, attachments, zip_root_folder(archive)) do |zip_filepath|
|
||||
ArchiveUploader.new(procedure: @procedure, filename: archive.filename(@procedure), filepath: zip_filepath)
|
||||
|
|
|
@ -35,7 +35,7 @@ class ProcedureExportService
|
|||
end
|
||||
|
||||
def to_zip
|
||||
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers, true)
|
||||
attachments = ActiveStorage::DownloadableFile.create_list_from_dossiers(dossiers, with_champs_private: true)
|
||||
|
||||
DownloadableFileService.download_and_zip(procedure, attachments, base_filename) do |zip_filepath|
|
||||
ArchiveUploader.new(procedure: procedure, filename: filename(:zip), filepath: zip_filepath).blob
|
||||
|
|
|
@ -41,42 +41,43 @@
|
|||
%li
|
||||
= link_to admin_procedure_path(procedure), class: 'fr-btn fr-icon-draft-line fr-btn--tertiary' do
|
||||
Modifier
|
||||
%li.dropdown{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.fr-btn--tertiary.dropdown-button.procedures-actions-btn{ data: { menu_button_target: 'button' } }
|
||||
|
||||
= render Dropdown::MenuComponent.new(wrapper: :li, button_options: { class: ['fr-btn--tertiary'] }, menu_options: { id: dom_id(procedure, :actions_menu)}) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
Actions
|
||||
.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' }, id: dom_id(procedure, :actions_menu) }
|
||||
%ul.dropdown-items.pl-0
|
||||
|
||||
- if !procedure.close? && !procedure.discarded?
|
||||
%li
|
||||
= link_to sanitize_url(procedure.brouillon? ? commencer_test_url(path: procedure.path) : commencer_url(path: procedure.path)), target: :blank, rel: :noopener do
|
||||
- menu.with_item do
|
||||
= link_to(sanitize_url(procedure.brouillon? ? commencer_test_url(path: procedure.path) : commencer_url(path: procedure.path)), target: :blank, rel: :noopener, role: 'menuitem') do
|
||||
%span.icon.in-progress
|
||||
.dropdown-description
|
||||
%h4= t('administrateurs.dropdown_actions.to_test')
|
||||
|
||||
- unless procedure.discarded?
|
||||
%li
|
||||
= link_to admin_procedure_clone_path(procedure.id), class: 'clone-btn', data: { method: :put } do
|
||||
- if !procedure.discarded?
|
||||
- menu.with_item do
|
||||
= link_to(admin_procedure_clone_path(procedure.id), role: 'menuitem', class: 'clone-btn', data: { method: :put }) do
|
||||
%span.icon.new-folder
|
||||
.dropdown-description
|
||||
%h4= t('administrateurs.dropdown_actions.to_clone')
|
||||
|
||||
- if procedure.publiee?
|
||||
%li
|
||||
= link_to admin_procedure_close_path(procedure_id: procedure.id) do
|
||||
- menu.with_item do
|
||||
= link_to(admin_procedure_close_path(procedure_id: procedure.id), role: 'menuitem') do
|
||||
%span.icon.archive
|
||||
.dropdown-description
|
||||
%h4= t('administrateurs.dropdown_actions.to_close')
|
||||
|
||||
- if procedure.can_be_deleted_by_administrateur? && !procedure.discarded?
|
||||
%li
|
||||
= link_to admin_procedure_path(procedure), method: :delete, data: { confirm: "Voulez-vous vraiment supprimer la démarche ? \nToute suppression est définitive et s'appliquera aux éventuels autres administrateurs de cette démarche !" } do
|
||||
- menu.with_item do
|
||||
= link_to admin_procedure_path(procedure), role: 'menuitem', method: :delete, data: { confirm: "Voulez-vous vraiment supprimer la démarche ? \nToute suppression est définitive et s'appliquera aux éventuels autres administrateurs de cette démarche !" } do
|
||||
%span.icon.refuse
|
||||
.dropdown-description
|
||||
%h4= t('administrateurs.dropdown_actions.delete')
|
||||
|
||||
- if procedure.discarded?
|
||||
%li
|
||||
= link_to restore_admin_procedure_path(procedure), method: :put do
|
||||
- menu.with_item do
|
||||
= link_to restore_admin_procedure_path(procedure), role: 'menuitem', method: :put do
|
||||
%span.icon.unarchive
|
||||
.dropdown-description
|
||||
%h4= t('administrateurs.dropdown_actions.restore')
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
%li= link_to("Dossier nº #{dossier.id}", expert_avis_path(avis.procedure, avis))
|
||||
|
||||
.header-actions
|
||||
%span.dropdown.print-menu-opener{ data: { controller: 'menu-button' } }
|
||||
%button.button.dropdown-button.icon-only{ data: { menu_button_target: 'button' } }
|
||||
%span.icon.attached
|
||||
%ul.print-menu.dropdown-content#print-pj-menu{ data: { menu_button_target: 'menu' } }
|
||||
%li= link_to "Télécharger le dossier et toutes ses pièces jointes", telecharger_pjs_expert_avis_path(avis.procedure, avis), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
||||
.fr-download
|
||||
= link_to telecharger_pjs_expert_avis_path(avis.procedure, avis), download: :download, class: "menu-item menu-link fr-download__link" do
|
||||
Télécharger le dossier et toutes ses pièces jointes
|
||||
%span.fr-download__detail
|
||||
ZIP
|
||||
|
||||
%nav.tabs
|
||||
%ul
|
||||
|
|
|
@ -1,21 +1,31 @@
|
|||
%ul.fr-btns-group.fr-btns-group--sm.fr-btns-group--inline-md.fr-btns-group--icon-right
|
||||
%li.dropdown.print-menu-opener{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.fr-btn--tertiary.fr-icon-printer-line.dropdown-button{ title: 'imprimer', 'aria-label': 'Imprimer', data: { menu_button_target: 'button' } } Imprimer
|
||||
%ul#print-menu.print-menu.dropdown-content{ data: { menu_button_target: 'menu' } }
|
||||
%li
|
||||
= link_to "Tout le dossier", print_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
||||
%li
|
||||
= link_to "Uniquement cet onglet", "#", onclick: "window.print()", class: "menu-item menu-link"
|
||||
%li
|
||||
= link_to "Export PDF", instructeur_dossier_path(dossier.procedure, dossier, format: :pdf), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
||||
- if dossier.geo_data?
|
||||
%li
|
||||
= link_to "Export GeoJSON", geo_data_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
||||
= render Dropdown::MenuComponent.new(wrapper: :li, menu_options: { id: 'print-menu'}, button_options: { class: ['fr-btn--tertiary', 'fr-icon-printer-line']}) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
Imprimer
|
||||
|
||||
%li.dropdown.print-menu-opener{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.fr-btn--tertiary.fr-icon-download-line.dropdown-button{ data: { menu_button_target: 'button', 'aria-label': 'Télécharger' } } Télécharger
|
||||
%ul#print-pj-menu.print-menu.dropdown-content{ data: { menu_button_target: 'menu' } }
|
||||
%li= link_to "Télécharger le dossier et toutes ses pièces jointes", telecharger_pjs_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
||||
- menu.with_item do
|
||||
= link_to print_instructeur_dossier_path(dossier.procedure, dossier), role: 'menuitem', target: "_blank", rel: "noopener", class: "menu-item menu-link" do
|
||||
Tout le dossier
|
||||
|
||||
- menu.with_item do
|
||||
= link_to '#', role: 'menuitem', onclick: "window.print()", class: "menu-item menu-link" do
|
||||
Uniquement cet onglet
|
||||
|
||||
- menu.with_item do
|
||||
= link_to instructeur_dossier_path(dossier.procedure, dossier, format: :pdf), target: "_blank", rel: "noopener", class: "menu-item menu-link", role: 'menuitem' do
|
||||
Export PDF
|
||||
|
||||
- if dossier.geo_data?
|
||||
- menu.with_item do
|
||||
= link_to geo_data_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link", role: 'menuitem' do
|
||||
Export GeoJSON
|
||||
|
||||
= render Dropdown::MenuComponent.new(wrapper: :li, menu_options: { id: 'print-pj-menu'}, button_options: { class: ['fr-btn--tertiary', 'fr-icon-download-line']}) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
Télécharger
|
||||
- menu.with_item do
|
||||
= link_to telecharger_pjs_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link", role: 'menuitem' do
|
||||
Télécharger le dossier et toutes ses pièces jointes
|
||||
|
||||
%li
|
||||
= render partial: "instructeurs/procedures/dossier_actions",
|
||||
|
|
|
@ -1,90 +1,77 @@
|
|||
.dropdown{ data: { controller: 'menu-button', popover: 'true', turbo_force: true } }
|
||||
-# Dropdown button title
|
||||
%button.fr-btn.dropdown-button{ class: button_or_label_class(dossier), data: { menu_button_target: 'button' } }
|
||||
= dossier_display_state dossier
|
||||
|
||||
-# Dropdown content
|
||||
#state-menu.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :div, wrapper_options: { data: {'turbo-force': true} }, button_options: { class: [button_or_label_class(dossier)] }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= dossier_display_state(dossier)
|
||||
|
||||
- if dossier.en_construction?
|
||||
-# ------------------------------------------------------
|
||||
-# EN CONSTRUCTION
|
||||
-# ------------------------------------------------------
|
||||
%ul.dropdown-items
|
||||
|
||||
%li.selected
|
||||
- menu.with_item(aria: {disabled:"true"}, class: 'selected') do
|
||||
%span.icon.edit
|
||||
.dropdown-description
|
||||
%h4 En construction
|
||||
Vous permettez à l'usager de modifier ses réponses au formulaire
|
||||
|
||||
%li{ 'data-turbo': 'true' }
|
||||
= link_to passer_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo_method: :post, turbo_confirm: "Confirmez-vous le passage en instruction de ce dossier ?" } do
|
||||
- menu.with_item('data-turbo': 'true') do
|
||||
= link_to(passer_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo_method: :post, turbo_confirm: "Confirmez-vous le passage en instruction de ce dossier ?", turbo: true }, role: 'menuitem') do
|
||||
%span.icon.in-progress
|
||||
.dropdown-description
|
||||
%h4 Passer en instruction
|
||||
L’usager ne pourra plus modifier le formulaire
|
||||
|
||||
- elsif dossier.en_instruction?
|
||||
-# ------------------------------------------------------
|
||||
-# EN INSTRUCTION
|
||||
-# ------------------------------------------------------
|
||||
%ul.dropdown-items
|
||||
|
||||
%li{ 'data-turbo': 'true' }
|
||||
= link_to repasser_en_construction_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo_method: :post, turbo_confirm: "Confirmez-vous le passage en construction de ce dossier ?" } do
|
||||
- menu.with_item('data-turbo': 'true') do
|
||||
= link_to(repasser_en_construction_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo_method: :post, turbo_confirm: "Confirmez-vous le passage en construction de ce dossier ?"}, role: 'menuitem') do
|
||||
%span.icon.edit
|
||||
.dropdown-description
|
||||
%h4 Repasser en construction
|
||||
Vous permettrez à l'usager de modifier ses réponses au formulaire
|
||||
|
||||
%li.selected
|
||||
- menu.with_item(aria: {disabled:"true"}, class: 'selected') do
|
||||
%span.icon.in-progress
|
||||
.dropdown-description
|
||||
%h4 En instruction
|
||||
L’usager ne peut modifier son dossier pendant l'instruction
|
||||
|
||||
%li
|
||||
%a{ href: '#', onclick: "DS.showMotivation(event, 'accept');" }
|
||||
- menu.with_item do
|
||||
= link_to('#', onclick: "DS.showMotivation(event, 'accept');", role: 'menuitem') do
|
||||
%span.icon.accept
|
||||
.dropdown-description
|
||||
%h4 Accepter
|
||||
L’usager sera notifié que son dossier a été accepté
|
||||
|
||||
%li
|
||||
%a{ href: '#', onclick: "DS.showMotivation(event, 'without-continuation');" }
|
||||
|
||||
- menu.with_item do
|
||||
= link_to('#', onclick: "DS.showMotivation(event, 'without-continuation');", role: 'menuitem') do
|
||||
%span.icon.without-continuation
|
||||
.dropdown-description
|
||||
%h4 Classer sans suite
|
||||
L’usager sera notifié que son dossier a été classé sans suite
|
||||
|
||||
%li
|
||||
%a{ href: '#', onclick: "DS.showMotivation(event, 'refuse');" }
|
||||
|
||||
- menu.with_item do
|
||||
= link_to('#', onclick: "DS.showMotivation(event, 'refuse');", role: 'menuitem') do
|
||||
%span.icon.refuse
|
||||
.dropdown-description
|
||||
%h4 Refuser
|
||||
L’usager sera notifié que son dossier a été refusé
|
||||
|
||||
- menu.with_form do
|
||||
= render partial: 'instructeurs/dossiers/state_button_motivation', locals: { dossier: dossier, popup_title: 'Accepter le dossier', placeholder: 'Expliquez au demandeur pourquoi ce dossier est accepté (facultatif)', popup_class: 'accept', process_action: 'accepter', title: 'Accepter', confirm: "Confirmez-vous l'acceptation ce dossier ?" }
|
||||
|
||||
- menu.with_form do
|
||||
= render partial: 'instructeurs/dossiers/state_button_motivation', locals: { dossier: dossier, popup_title: 'Classer le dossier sans suite', placeholder: 'Expliquez au demandeur pourquoi ce dossier est classé sans suite (obligatoire)', popup_class: 'without-continuation', process_action: 'classer_sans_suite', title: 'Classer sans suite', confirm: 'Confirmez-vous le classement sans suite de ce dossier ?' }
|
||||
|
||||
- menu.with_form do
|
||||
= render partial: 'instructeurs/dossiers/state_button_motivation', locals: { dossier: dossier, popup_title: 'Refuser le dossier', placeholder: 'Expliquez au demandeur pourquoi ce dossier est refusé (obligatoire)', popup_class: 'refuse', process_action: 'refuser', title: 'Refuser', confirm: 'Confirmez-vous le refus de ce dossier ?' }
|
||||
|
||||
- elsif dossier.termine?
|
||||
-# ---------------------------------------------------
|
||||
-# TERMINÉ
|
||||
-# ---------------------------------------------------
|
||||
%ul.dropdown-items
|
||||
- if dossier.motivation.present?
|
||||
%li.inactive
|
||||
- menu.with_item(class: 'inactive') do
|
||||
%span.icon.info
|
||||
.dropdown-description
|
||||
%h4 Motivation
|
||||
%p « #{dossier.motivation} »
|
||||
|
||||
- if dossier.justificatif_motivation.attached?
|
||||
%li.inactive
|
||||
- menu.with_item(class: 'inactive') do
|
||||
%span.icon.justificatif
|
||||
.dropdown-description
|
||||
%h4 Justificatif
|
||||
|
@ -92,29 +79,29 @@
|
|||
= render partial: 'users/dossiers/show/download_justificatif', locals: { dossier: dossier }
|
||||
|
||||
- if dossier.attestation.present?
|
||||
%li
|
||||
= link_to attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener' do
|
||||
- menu.with_item do
|
||||
= link_to(attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', role: 'menuitem') do
|
||||
%span.icon.preview
|
||||
.dropdown-description
|
||||
%h4 Voir l’attestation
|
||||
%p Cette attestation a été envoyée automatiquement au demandeur.
|
||||
|
||||
- if dossier.can_repasser_en_instruction?
|
||||
%li{ 'data-turbo': 'true' }
|
||||
= link_to repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo_method: :post, turbo_confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?" } do
|
||||
- menu.with_item do
|
||||
= link_to(repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo_method: :post, turbo_confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?", turbo: true }, role: 'menuitem') do
|
||||
%span.icon.in-progress
|
||||
.dropdown-description
|
||||
%h4 Repasser en instruction
|
||||
L’usager sera notifié que son dossier est réexaminé.
|
||||
- elsif dossier.user_deleted?
|
||||
%li
|
||||
- menu.with_item do
|
||||
%span.icon.info
|
||||
.dropdown-description
|
||||
%h4 En attente d’archivage
|
||||
L’usager a supprimé son compte. Vous pouvez archiver puis supprimer le dossier.
|
||||
|
||||
%li
|
||||
= link_to instructeur_dossier_path(dossier.procedure, dossier), method: :delete do
|
||||
- menu.with_item do
|
||||
= link_to(instructeur_dossier_path(dossier.procedure, dossier), method: :delete, role: 'menuitem') do
|
||||
%span.icon.delete
|
||||
.dropdown-description
|
||||
%h4 Supprimer le dossier
|
||||
|
|
|
@ -2,34 +2,37 @@
|
|||
= link_to restore_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, class: "fr-btn fr-btn--secondary" do
|
||||
= t('views.instructeurs.dossiers.restore')
|
||||
- elsif close_to_expiration || Dossier::TERMINE.include?(state)
|
||||
%li.dropdown.user-dossier-actions{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.fr-mb-0.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :li, button_options: { class: ['fr-mb-0']}, menu_options: { id: "dossier_#{dossier_id}_actions_menu", class: 'user-dossier-actions' }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
Actions
|
||||
.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' }, id: "dossier_#{dossier_id}_actions_menu" }
|
||||
%ul.dropdown-items
|
||||
|
||||
- if close_to_expiration
|
||||
%li
|
||||
= link_to repousser_expiration_instructeur_dossier_path(procedure_id, dossier_id), method: :post do
|
||||
- menu.with_item do
|
||||
= link_to(repousser_expiration_instructeur_dossier_path(procedure_id, dossier_id), method: :post, role: 'menuitem') do
|
||||
%span.icon.standby
|
||||
%span.dropdown-description= t('instructeurs.dossiers.header.banner.button_delay_expiration')
|
||||
|
||||
- if archived
|
||||
%li
|
||||
= link_to unarchive_instructeur_dossier_path(procedure_id, dossier_id), method: :patch do
|
||||
- menu.with_item do
|
||||
= link_to( unarchive_instructeur_dossier_path(procedure_id, dossier_id), role: 'menuitem', method: :patch) do
|
||||
%span.icon.unarchive
|
||||
%span.dropdown-description
|
||||
Désarchiver le dossier
|
||||
|
||||
- else
|
||||
%li
|
||||
= link_to archive_instructeur_dossier_path(procedure_id, dossier_id), method: :patch do
|
||||
- menu.with_item do
|
||||
= link_to( archive_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, role: 'menuitem') do
|
||||
%span.icon.archive
|
||||
%span.dropdown-description
|
||||
Archiver le dossier
|
||||
%li.danger
|
||||
= link_to instructeur_dossier_path(procedure_id, dossier_id), method: :delete do
|
||||
|
||||
- menu.with_item(class: 'danger') do
|
||||
= link_to(instructeur_dossier_path(procedure_id, dossier_id), method: :delete, role: 'menuitem') do
|
||||
%span.icon.delete
|
||||
%span.dropdown-description
|
||||
= t('views.instructeurs.dossiers.delete_dossier')
|
||||
|
||||
|
||||
- elsif Dossier::EN_CONSTRUCTION_OU_INSTRUCTION.include?(state)
|
||||
- if dossier_is_followed
|
||||
= link_to unfollow_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, class: 'fr-btn fr-btn--secondary fr-icon-star-fill' do
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
%span.dropdown{ data: { controller: 'menu-button', popover: 'true' } }
|
||||
%button.fr-btn.fr-btn--tertiary.fr-btn--sm.fr-mr-2w.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :div, button_options: { class: ['fr-btn--secondary', 'fr-btn--sm', 'fr-mr-1w'] }, menu_options: { id: 'filter-menu', class:['left-aligned'] }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= t('views.instructeurs.dossiers.filters.title')
|
||||
#filter-menu.dropdown-content.left-aligned.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||
|
||||
- menu.with_form do
|
||||
= render Dossiers::FilterComponent.new(procedure: procedure, procedure_presentation: @procedure_presentation, statut: statut)
|
||||
|
||||
|
|
|
@ -62,10 +62,10 @@
|
|||
= render Dossiers::NotifiedToggleComponent.new(procedure: @procedure, procedure_presentation: @procedure_presentation)
|
||||
|
||||
.fr-ml-auto
|
||||
%span.dropdown{ data: { controller: 'menu-button', popover: 'true' } }
|
||||
%button.fr-btn.fr-btn--sm.fr-btn--tertiary.dropdown-button.fr-ml-1w{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :span, button_options: { class: ['fr-btn--sm', 'fr-btn--secondary'] }, menu_options: { id: 'custom-menu' }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= t('views.instructeurs.dossiers.personalize')
|
||||
#custom-menu.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||
- menu.with_form do
|
||||
= form_tag update_displayed_fields_instructeur_procedure_path(@procedure), method: :patch, class: 'dropdown-form large columns-form' do
|
||||
= hidden_field_tag :values, nil
|
||||
= react_component("ComboMultiple",
|
||||
|
@ -120,6 +120,7 @@
|
|||
|
||||
%th.action-col.follow-col
|
||||
Actions
|
||||
|
||||
%tr
|
||||
|
||||
%tbody
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- invites = dossier.invites.load
|
||||
.dropdown.invite-user-action{ data: { controller: 'menu-button', popover: 'true' } }
|
||||
%button.button.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :span, wrapper_options: {class: 'invite-user-action'}, button_options: { class: ['fr-btn--secondary'] }, menu_options: { id: 'invite-content' }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
%span.icon.person
|
||||
- if invites.present?
|
||||
= t('views.invites.dropdown.view_invited_people')
|
||||
|
@ -10,6 +10,5 @@
|
|||
= t('views.invites.dropdown.invite_to_view')
|
||||
- else
|
||||
= t('views.invites.dropdown.invite_to_edit')
|
||||
|
||||
#invite-content.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||
- menu.with_form do
|
||||
= render partial: "invites/form", locals: { dossier: dossier, invites: invites }
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#search-modal.fr-header__search.fr-modal
|
||||
.fr-container.fr-container-lg--fluid
|
||||
%button.fr-btn--close.fr-btn{ "aria-controls" => "search-modal", :title => t('close_modal', scope: [:layouts, :header]) }= t('close_modal', scope: [:layouts, :header])
|
||||
#search-473.fr-search-bar{ :role => "search" }
|
||||
= form_tag "#{search_endpoint}", method: :get, class: "flex width-100" do
|
||||
#search-473.fr-search-bar
|
||||
= form_tag "#{search_endpoint}", method: :get, :role => "search", class: "flex width-100" do
|
||||
= label_tag "q", t('views.users.dossiers.search.search_file'), class: 'fr-label'
|
||||
= text_field_tag "q", "#{@search_terms if @search_terms.present?}", placeholder: t('views.users.dossiers.search.search_file'), aria: { label: t('views.users.dossiers.search.search_file') }, class: "fr-input"
|
||||
= text_field_tag "q", "#{@search_terms if @search_terms.present?}", placeholder: t('views.users.dossiers.search.placeholder'), class: "fr-input"
|
||||
%button.fr-btn{ title: t('views.users.dossiers.search.search_file') }
|
||||
= image_tag "icons/search-blue.svg", alt: t('views.users.dossiers.search.search_file'), 'aria-hidden':'true', width: 24, height: 24, loading: 'lazy'
|
||||
|
||||
|
||||
= t('views.users.dossiers.search.search_file')
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
.no-procedure
|
||||
= image_tag "landing/hero/dematerialiser.svg", class: "paperless-logo", alt: ""
|
||||
.baseline.center
|
||||
%p
|
||||
%span.simple= t('.line1')
|
||||
%br
|
||||
= t('.line2')
|
||||
%br
|
||||
= t('.line3')
|
||||
.no-procedure-presentation
|
||||
%p.simple= t('.line1')
|
||||
%p= t('.line2')
|
||||
%p= t('.line3')
|
||||
%hr
|
||||
%p
|
||||
%span.small-simple= t('.are_you_new', app_name: APPLICATION_NAME.gsub("-","‑")).html_safe
|
||||
%br
|
||||
%br
|
||||
%p.small-simple= t('.are_you_new', app_name: APPLICATION_NAME.gsub("-","‑")).html_safe
|
||||
= link_to t('views.users.sessions.new.find_procedure'), t("links.common.faq.comment_trouver_ma_demarche_url"), title: new_tab_suffix(t('views.users.sessions.new.find_procedure')), class: "fr-btn fr-btn--secondary", **external_link_attributes
|
||||
|
|
|
@ -12,11 +12,8 @@
|
|||
%p
|
||||
%strong
|
||||
= t('.procedure_management')
|
||||
%br
|
||||
= service.nom
|
||||
%br
|
||||
= service.organisme
|
||||
%br
|
||||
= service.adresse
|
||||
%td{ width: "50%", valign: "top" }
|
||||
%p
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
= type_de_champ.possible_values_sentence
|
||||
%br
|
||||
- if type_de_champ.too_many_possible_values?
|
||||
= link_to "Voir toutes les valeurs possibles", prefill_type_de_champ_path(prefill_description.path, type_de_champ)
|
||||
= link_to t("views.prefill_descriptions.edit.possible_values.link.text"), prefill_type_de_champ_path(prefill_description.path, type_de_champ), title: new_tab_suffix(t("views.prefill_descriptions.edit.possible_values.link.title")), **external_link_attributes
|
||||
%tr{ class: prefillable ? "" : "fr-text-mention--grey" }
|
||||
%th
|
||||
= t("views.prefill_descriptions.edit.examples.title")
|
||||
|
|
|
@ -67,18 +67,18 @@
|
|||
|
||||
- if instructeur_dossier && expert_dossier
|
||||
%td.action-col.follow-col
|
||||
.dropdown{ data: { controller: 'menu-button' } }
|
||||
%button.button.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :div, button_options: {class: ['fr-btn--sm']}) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
Actions
|
||||
.dropdown-content{ data: { menu_button_target: 'menu' } }
|
||||
%ul.dropdown-items
|
||||
%li
|
||||
= link_to(instructeur_dossier_path(procedure_id, p.dossier_id)) do
|
||||
|
||||
- menu.with_item do
|
||||
= link_to(instructeur_dossier_path(procedure_id, p.dossier_id), role: 'menuitem') do
|
||||
%span.icon.in-progress>
|
||||
.dropdown-description
|
||||
Voir le dossier
|
||||
%li
|
||||
= link_to(expert_avis_path(procedure_id, @dossier_avis_ids_h[p.dossier_id])) do
|
||||
|
||||
- menu.with_item do
|
||||
= link_to(expert_avis_path(procedure_id, @dossier_avis_ids_h[p.dossier_id]), role: 'menuitem') do
|
||||
%span.icon.in-progress>
|
||||
.dropdown-description
|
||||
Donner mon avis
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
.dropdown.help-dropdown{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :span, wrapper_options: { class: ['help-dropdown']}, menu_options: { id: "help-menu" }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= t('help')
|
||||
#help-menu.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||
%ul.dropdown-items
|
||||
- title = dossier.brouillon? ? "Besoin d’aide pour remplir votre dossier ?" : "Une question sur votre dossier ?"
|
||||
|
||||
- if dossier.messagerie_available?
|
||||
= render partial: 'shared/help/dropdown_items/messagerie_item',
|
||||
locals: { dossier: dossier, title: title }
|
||||
- menu.with_item do
|
||||
= render partial: 'shared/help/dropdown_items/messagerie_item', locals: { dossier: dossier, title: title }
|
||||
|
||||
- elsif dossier.procedure.service.present?
|
||||
- menu.with_item do
|
||||
= render partial: 'shared/help/dropdown_items/service_item',
|
||||
locals: { service: dossier.procedure.service, title: title }
|
||||
|
||||
- menu.with_item do
|
||||
= render partial: 'shared/help/dropdown_items/faq_item'
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
.dropdown.help-dropdown{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :span, wrapper_options: { class: ['help-dropdown']}, menu_options: { id: "help-menu" }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= t('help')
|
||||
#help-menu.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||
%ul.dropdown-items
|
||||
|
||||
- menu.with_item do
|
||||
= render partial: 'shared/help/dropdown_items/faq_item'
|
||||
- menu.with_item do
|
||||
= render partial: 'shared/help/dropdown_items/email_item'
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
.dropdown.help-dropdown{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :span, wrapper_options: { class: ['help-dropdown']}, menu_options: { id: "help-menu" }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= t('help')
|
||||
#help-menu.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||
%ul.dropdown-items
|
||||
- if procedure.service.present?
|
||||
= render partial: 'shared/help/dropdown_items/service_item',
|
||||
locals: { service: procedure.service, title: "Une question sur cette démarche ?" }
|
||||
|
||||
- if procedure.service.present?
|
||||
- menu.with_item do
|
||||
= render partial: 'shared/help/dropdown_items/service_item', locals: { service: procedure.service, title: "Une question sur cette démarche ?" }
|
||||
- menu.with_item do
|
||||
= render partial: 'shared/help/dropdown_items/faq_item'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%li
|
||||
= mail_to CONTACT_EMAIL do
|
||||
%li{ role: 'none' }
|
||||
= mail_to CONTACT_EMAIL, role: 'menuitem' do
|
||||
%span.icon.mail
|
||||
.dropdown-description
|
||||
%span.help-dropdown-title
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
%li
|
||||
= link_to t("links.common.faq.url"), title: new_tab_suffix(t('help_dropdown.general_title')), **external_link_attributes do
|
||||
= link_to t("links.common.faq.url"), title: new_tab_suffix(t('help_dropdown.general_title')), **external_link_attributes, role: 'menuitem' do
|
||||
%span.icon.help
|
||||
.dropdown-description
|
||||
%span.help-dropdown-title
|
||||
= t('help_dropdown.problem_title')
|
||||
%p
|
||||
= t('help_dropdown.problem_description')
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
%li
|
||||
= link_to messagerie_dossier_path(dossier) do
|
||||
= link_to messagerie_dossier_path(dossier), role: 'menuitem' do
|
||||
%span.icon.mail
|
||||
.dropdown-description
|
||||
%span.help-dropdown-title= title
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
%li.help-dropdown-service
|
||||
%span.icon.person
|
||||
.dropdown-description
|
||||
%span.icon.person
|
||||
.dropdown-description
|
||||
%span.help-dropdown-title= title
|
||||
.help-dropdown-service-action
|
||||
%p Contactez directement l’administration :
|
||||
%p.help-dropdown-service-item
|
||||
%span.icon.small.mail
|
||||
= link_to service.email, "mailto:#{service.email}"
|
||||
= link_to service.email, "mailto:#{service.email}", role: 'menuitem'
|
||||
%p.help-dropdown-service-item
|
||||
%span.icon.small.phone
|
||||
= link_to service.telephone, service.telephone_url
|
||||
= link_to service.telephone, service.telephone_url, role: 'menuitem'
|
||||
%p.help-dropdown-service-item
|
||||
%span.icon.small.clock
|
||||
= service.horaires
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
= form_tag contact_path, method: :post, multipart: true, class: 'fr-form-group', data: {controller: :support } do
|
||||
|
||||
.description
|
||||
%h2= t('.intro_html')
|
||||
%br
|
||||
.recommandations
|
||||
%h2
|
||||
= t('.intro_html')
|
||||
%p.mandatory-explanation= t('asterisk_html', scope: [:utils])
|
||||
|
||||
- if !user_signed_in?
|
||||
|
@ -34,7 +35,7 @@
|
|||
|
||||
- if link.present?
|
||||
.support.card.featured.mb-4.ml-4.hidden{ id: "card-#{question_type}", "aria-hidden": true , data: { "support-target": "content" } }
|
||||
.card-title
|
||||
%p.card-title
|
||||
= t('.our_answer')
|
||||
.card-content
|
||||
-# i18n-tasks-use t("support.index.#{question_type}.answer_html")
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
%li
|
||||
- horaires = "#{I18n.t('users.procedure_footer.contact.schedule.prefix')}#{formatted_horaires(service.horaires)}"
|
||||
= link_to service.telephone_url, class: 'fr-footer__top-link' do
|
||||
%p
|
||||
= I18n.t('users.procedure_footer.contact.phone.link', service_telephone: service.telephone)
|
||||
%br
|
||||
%p
|
||||
= horaires
|
||||
%li
|
||||
= link_to I18n.t('users.procedure_footer.contact.stats.link'), statistiques_path(procedure.path), class: 'fr-footer__top-link', rel: 'noopener'
|
||||
|
|
|
@ -4,49 +4,51 @@
|
|||
- has_transfer_action = dossier.user == current_user
|
||||
- has_actions = has_edit_action || has_delete_action || has_new_dossier_action || has_transfer_action
|
||||
|
||||
|
||||
|
||||
- if has_actions
|
||||
.dropdown.user-dossier-actions{ data: { controller: 'menu-button' } }
|
||||
%button.fr-btn.fr-btn--secondary.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :div, wrapper_options: {class: 'invite-user-actions'}, menu_options: {id: dom_id(dossier, :actions_menu)}, button_options: {class: 'fr-btn--sm fr-btn--secondary'}) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= t('views.users.dossiers.dossier_action.actions')
|
||||
.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' }, id: dom_id(dossier, :actions_menu) }
|
||||
%ul.dropdown-items
|
||||
|
||||
- if has_edit_action
|
||||
- if dossier.brouillon?
|
||||
%li
|
||||
= link_to(url_for_dossier(dossier)) do
|
||||
- menu.with_item do
|
||||
= link_to(url_for_dossier(dossier), role: 'menuitem') do
|
||||
%span.icon.edit
|
||||
.dropdown-description
|
||||
= t('views.users.dossiers.dossier_action.edit_draft')
|
||||
- else
|
||||
%li
|
||||
= link_to modifier_dossier_path(dossier) do
|
||||
- menu.with_item do
|
||||
= link_to(modifier_dossier_path(dossier), role: 'menuitem') do
|
||||
%span.icon.edit
|
||||
.dropdown-description
|
||||
= t('views.users.dossiers.dossier_action.edit_dossier')
|
||||
|
||||
- if has_transfer_action
|
||||
%li
|
||||
= link_to transferer_dossier_path(dossier) do
|
||||
- menu.with_item do
|
||||
= link_to(transferer_dossier_path(dossier), role: 'menuitem') do
|
||||
%span.icon.person
|
||||
.dropdown-description
|
||||
= t('views.users.dossiers.dossier_action.transfer_dossier')
|
||||
|
||||
- if has_new_dossier_action
|
||||
%li
|
||||
= link_to procedure_lien(dossier.procedure) do
|
||||
- menu.with_item do
|
||||
= link_to(procedure_lien(dossier.procedure), role: 'menuitem') do
|
||||
%span.icon.new-folder
|
||||
.dropdown-description
|
||||
= t('views.users.dossiers.dossier_action.start_other_dossier')
|
||||
%li
|
||||
= link_to clone_dossier_path(dossier), method: :post do
|
||||
|
||||
- menu.with_item do
|
||||
= link_to(clone_dossier_path(dossier), method: :post, role: 'menuitem') do
|
||||
%span.icon.new-folder
|
||||
.dropdown-description
|
||||
= t('views.users.dossiers.dossier_action.clone')
|
||||
|
||||
- if has_delete_action
|
||||
%li.danger
|
||||
= link_to delete_dossier_dossier_path(dossier), method: :patch, data: { disable: true, confirm: "En continuant, vous allez supprimer ce dossier ainsi que les informations qu’il contient. Toute suppression entraîne l’annulation de la démarche en cours.\n\nConfirmer la suppression ?" } do
|
||||
- menu.with_item(class: 'danger') do
|
||||
= link_to(delete_dossier_dossier_path(dossier), role: 'menuitem', method: :patch, data: { disable: true, confirm: "En continuant, vous allez supprimer ce dossier ainsi que les informations qu’il contient. Toute suppression entraîne l’annulation de la démarche en cours.\n\nConfirmer la suppression ?" }) do
|
||||
|
||||
%span.icon.delete
|
||||
.dropdown-description
|
||||
= t('views.users.dossiers.dossier_action.delete_dossier')
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.dropdown.edit-identity-action{ data: { controller: 'menu-button', popover: 'true' } }
|
||||
%button.button.dropdown-button{ data: { menu_button_target: 'button' } }
|
||||
= render Dropdown::MenuComponent.new(wrapper: :div, wrapper_options: {class: ['edit-identity-action']}, menu_options: { class:['edit-identity-content'] }) do |menu|
|
||||
- menu.with_button_inner_html do
|
||||
= t("views.shared.dossiers.demande.my_identity")
|
||||
|
||||
#edit-identity-content.dropdown-content.fade-in-down{ data: { menu_button_target: 'menu' } }
|
||||
- menu.with_form do
|
||||
- if dossier.procedure.for_individual
|
||||
= render partial: "shared/dossiers/identite_individual", locals: { individual: dossier.individual }
|
||||
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
|
||||
.container
|
||||
- if !@dossier.read_only?
|
||||
= link_to t('views.users.dossiers.demande.edit_dossier'), modifier_dossier_path(@dossier), class: 'button accepted edit-form', title: "Modifier mon dossier tant qu'il n'est pas passé en instruction"
|
||||
= link_to t('views.users.dossiers.demande.edit_dossier'), modifier_dossier_path(@dossier), class: 'fr-btn fr-btn-sm', 'title'=> "Modifier mon dossier tant qu'il n'est pas passé en instruction"
|
||||
.clearfix
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
.header-actions
|
||||
= render partial: 'invites/dropdown', locals: { dossier: dossier }
|
||||
- if dossier.can_be_updated_by_user? && !current_page?(modifier_dossier_path(dossier))
|
||||
= link_to t('views.users.dossiers.show.header.edit_dossier'), modifier_dossier_path(dossier), class: 'button accepted edit-form',
|
||||
= link_to t('views.users.dossiers.show.header.edit_dossier'), modifier_dossier_path(dossier), class: 'fr-btn fr-btn-sm',
|
||||
title: { label: t('views.users.dossiers.show.header.edit_dossier_title') }
|
||||
= render(partial: 'users/dossiers/show/print_dossier', locals: { dossier: dossier })
|
||||
|
||||
|
|
|
@ -1,6 +1 @@
|
|||
.dropdown.print-menu-opener{ data: { controller: 'menu-button' } }
|
||||
%button.button.dropdown-button.icon-only{ title: t('views.users.dossiers.show.header.print'), 'aria-label': 'imprimer', data: { menu_button_target: 'button' } }
|
||||
%span.icon.printer
|
||||
%ul#print-menu.print-menu.dropdown-content{ data: { menu_button_target: 'menu' } }
|
||||
%li
|
||||
= link_to t('views.users.dossiers.show.header.print_dossier'), dossier_path(dossier, format: :pdf), target: "_blank", rel: "noopener", class: "menu-item menu-link"
|
||||
= link_to t('views.users.dossiers.show.header.print'), dossier_path(dossier, format: :pdf), target: "_blank", rel: "noopener", title: t('views.users.dossiers.show.header.print_dossier'), class: 'fr-btn fr-icon-printer-line fr-btn--tertiary'
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
= turbo_stream.hide_all(@to_hide)
|
||||
- @to_update.each do |champ|
|
||||
= fields_for champ.input_name, champ do |form|
|
||||
= turbo_stream.morph champ.input_group_id do
|
||||
= turbo_stream.replace champ.input_group_id do
|
||||
= render EditableChamp::EditableChampComponent.new champ:, form:
|
||||
|
||||
= turbo_stream.remove_all(".editable-champ .spinner-removable");
|
||||
|
|
|
@ -112,6 +112,9 @@ en:
|
|||
champ_remove: Remove
|
||||
champ_unavailable: Unavailable
|
||||
possible_values:
|
||||
link:
|
||||
title: All possible values
|
||||
text: See all possible values
|
||||
title: Values
|
||||
text_html: A short text
|
||||
textarea_html: A long text
|
||||
|
@ -314,7 +317,8 @@ en:
|
|||
demande:
|
||||
edit_dossier: "Edit file"
|
||||
search:
|
||||
search_file: Search a file
|
||||
placeholder: Search a file
|
||||
search_file: Search
|
||||
index:
|
||||
dossiers: "Files"
|
||||
dossiers_list:
|
||||
|
|
|
@ -103,6 +103,9 @@ fr:
|
|||
champ_remove: Retirer
|
||||
champ_unavailable: Indisponible
|
||||
possible_values:
|
||||
link:
|
||||
title: Toutes les valeurs possibles
|
||||
text: Voir toutes les valeurs possibles
|
||||
title: Valeurs
|
||||
text_html: Un texte court
|
||||
textarea_html: Un texte long
|
||||
|
@ -310,7 +313,8 @@ fr:
|
|||
demande:
|
||||
edit_dossier: "Modifier le dossier"
|
||||
search:
|
||||
search_file: Rechercher un dossier
|
||||
placeholder: Rechercher un dossier
|
||||
search_file: Rechercher
|
||||
index:
|
||||
dossiers: "Dossiers"
|
||||
dossiers_list:
|
||||
|
|
|
@ -2,7 +2,8 @@ en:
|
|||
support:
|
||||
index:
|
||||
contact: Contact
|
||||
intro_html: Contact us via this form and we will answer you as quickly as possible.<br>Make sure you provide all the required information so we can help you in the best way.
|
||||
intro_html: "<p>Contact us via this form and we will answer you as quickly as possible.</p>
|
||||
<p>Make sure you provide all the required information so we can help you in the best way.</p>"
|
||||
your_question: Your question
|
||||
our_answer: 👉 Our answer
|
||||
notice_pj_product: A screenshot can help us identify the element to improve.
|
||||
|
@ -10,35 +11,28 @@ en:
|
|||
procedure_info:
|
||||
question: I've encountered a problem while completing my application
|
||||
answer_html: "<p>Are you sure that all the mandatory fields (<span class= mandatory> * </span>) are properly filled?
|
||||
<p>If you have questions about the information requested, contact the service in charge of the procedure.</p>
|
||||
<p><a href=%{link_procedure_info}>Find more information</a></p>"
|
||||
<p>If you have questions about the information requested, <a href=\"%{link_procedure_info}\">contact the service in charge of the procedure (FAQ)</a>.</p>"
|
||||
instruction_info:
|
||||
question: I have a question about the instruction of my application
|
||||
answer_html: "<p>If you have questions about the instruction of your application (response delay for example), contact directly the instructor via our mail system.</p>
|
||||
<p><a href=%{link_instruction_info}>Find more information</a></p>
|
||||
<br>
|
||||
answer_html: "<p>If you have questions about the instruction of your application (response delay for example), <a href=\"%{link_instruction_info}\">contact directly the instructor via our mail system (FAQ)</a>.</p>
|
||||
<p>If you are facing technical issues on the website, use the form below. We will not be able to inform you about the instruction of your application.</p>"
|
||||
product:
|
||||
question: I have an idea to improve the website
|
||||
answer_html: "<p>Got an idea? Please check our <strong>enhancement dashboard</strong></p>
|
||||
answer_html: "<p>Got an idea? <a href=\"%{link_product}\" rel=\"noopener noreferrer\" target=\"_blank\" title=\"Open features dashboard - New tab\">Please check our enhancement dashboard</a> :</p>
|
||||
<ul><li>Vote for your priority improvements</li>
|
||||
<li>Share your own ideas</li></ul>
|
||||
<p><strong><a href=%{link_product}>➡ Access the enhancement dashboard</a></strong></p>"
|
||||
<li>Share your own ideas</li></ul>"
|
||||
lost_user:
|
||||
question: I am having trouble finding the procedure I am looking for
|
||||
answer_html: "<p>We invite you to contact the administration in charge of the procedure so they can provide you the link.
|
||||
It should look like this: %{base_url}/commencer/NOM_DE_LA_DEMARCHE.</p>
|
||||
<br>
|
||||
<p>You can find here the most popular procedures (licence, detr, etc.) :</p>
|
||||
<p><a href=%{link_lost_user}>%{link_lost_user}</a></p>"
|
||||
It should look like this: <code>%{base_url}/commencer/NOM_DE_LA_DEMARCHE</code>.</p>
|
||||
<p>You can <a href=\"%{link_lost_user}\">find here the most popular procedures (licence, detr, etc.)</a>.</p>"
|
||||
other:
|
||||
question: Other topic
|
||||
admin:
|
||||
your_question: Your question
|
||||
admin_intro_html: "<p>As an administration, you can contact us through this form. We'll answer you as quickly as possibly by e-mail or phone.</p>
|
||||
<br>
|
||||
<p><strong>Caution, this form is dedicated to public bodies only.</strong>
|
||||
It does not concern individuals, companies nor associations (except those recognised of public utility). If you belong to one of these categories, contact us <a href=%{contact_path}>here</a>.</p>"
|
||||
It does not concern individuals, companies nor associations (except those recognised of public utility). If you belong to one of these categories, contact us <a href=\"%{contact_path}\">here</a>.</p>"
|
||||
contact_team: Contact our team
|
||||
pro_phone_number: Professional phone number (direct line)
|
||||
pro_mail: Professional email address
|
||||
|
|
|
@ -2,7 +2,8 @@ fr:
|
|||
support:
|
||||
index:
|
||||
contact: Contact
|
||||
intro_html: Contactez-nous via ce formulaire et nous vous répondrons dans les plus brefs délais.<br>Pensez bien à nous donner le plus d’informations possible pour que nous puissions vous aider au mieux.
|
||||
intro_html: "<p>Contactez-nous via ce formulaire et nous vous répondrons dans les plus brefs délais.</p>
|
||||
<p>Pensez bien à nous donner le plus d’informations possible pour que nous puissions vous aider au mieux.</p>"
|
||||
your_question: Votre question
|
||||
our_answer: 👉 Notre réponse
|
||||
notice_pj_product: Une capture d’écran peut nous aider à identifier plus facilement l’endroit à améliorer.
|
||||
|
@ -10,35 +11,28 @@ fr:
|
|||
procedure_info:
|
||||
question: J’ai un problème lors du remplissage de mon dossier
|
||||
answer_html: "<p>Avez-vous bien vérifié que tous les champs obligatoires (<span class= mandatory> * </span>) sont remplis ?
|
||||
<p>Si vous avez des questions sur les informations à saisir, contactez les services en charge de la démarche.</p>
|
||||
<p><a href=%{link_procedure_info}>En savoir plus</a></p>"
|
||||
<p>Si vous avez des questions sur les informations à saisir, <a href=\"%{link_procedure_info}\">contactez les services en charge de la démarche (FAQ)</a>.</p>"
|
||||
instruction_info:
|
||||
question: J’ai une question sur l’instruction de mon dossier
|
||||
answer_html: "<p>Si vous avez des questions sur l’instruction de votre dossier (par exemple sur les délais), nous vous invitons à contacter directement les services qui instruisent votre dossier par votre messagerie.</p>
|
||||
<p><a href=%{link_instruction_info}>En savoir plus</a></p>
|
||||
<br>
|
||||
answer_html: "<p>Si vous avez des questions sur l’instruction de votre dossier (par exemple sur les délais), nous vous invitons à <a href=\"%{link_instruction_info}\">contacter directement les services qui instruisent votre dossier par votre messagerie (FAQ)</a>.</p>
|
||||
<p>Si vous souhaitez poser une question pour un problème technique sur le site, utilisez le formulaire ci-dessous. Nous ne pourrons pas vous renseigner sur l’instruction de votre dossier.</p>"
|
||||
product:
|
||||
question: J’ai une idée d’amélioration pour votre site
|
||||
answer_html: "<p>Une idée ? Pensez à consulter notre <strong>tableau de bord des améliorations</strong></p>
|
||||
<ul><li>Votez pour vos améliorations prioritaires;</li>
|
||||
<li>Proposez votre propre idée.</li></ul>
|
||||
<p><strong><a href=%{link_product}>➡ Accéder au tableau des améliorations</a></strong></p>"
|
||||
answer_html: "<p>Une idée ? Pensez à <a href=\"%{link_product}\" rel=\"noopener noreferrer\" target=\"_blank\" title=\"Ouvrir le tableau des évolutions - Nouvel onglet\">consulter notre tableau de bord des améliorations</a> :</p>
|
||||
<ul><li>Votez pour vos améliorations prioritaires,</li>
|
||||
<li>Proposez votre propre idée.</li></ul>"
|
||||
lost_user:
|
||||
question: Je ne trouve pas la démarche que je veux faire
|
||||
answer_html: "<p>Nous vous invitons à contacter l’administration en charge de votre démarche pour qu’elle vous indique le lien à suivre. Celui-ci devrait ressembler à cela : %{base_url}/commencer/NOM_DE_LA_DEMARCHE.</p>
|
||||
<br>
|
||||
<p>Vous pouvez aussi consulter ici la liste de nos démarches les plus frequentes (permis, detr etc) :</p>
|
||||
<p><a href=%{link_lost_user}>%{link_lost_user}</a></p>"
|
||||
answer_html: "<p>Nous vous invitons à contacter l’administration en charge de votre démarche pour qu’elle vous indique le lien à suivre. Celui-ci devrait ressembler à cela : <code>%{base_url}/commencer/NOM_DE_LA_DEMARCHE</code>.</p>
|
||||
<p>Vous pouvez aussi <a href=\"%{link_lost_user}\">consulter ici la liste de nos démarches les plus fréquentes (permis, detr etc)</a>.</p>"
|
||||
other:
|
||||
question: Autre sujet
|
||||
admin:
|
||||
your_question: Votre question
|
||||
admin_intro_html: "<p>En tant qu’administration, vous pouvez nous contactez via ce formulaire. Nous vous répondrons dans les plus brefs délais, par email ou par téléphone.</p>
|
||||
<br>
|
||||
<p><strong>Attention, ce formulaire est réservé uniquement aux organismes publics.</strong>
|
||||
Il ne concerne ni les particuliers, ni les entreprises, ni les associations (sauf celles reconnues d’utilité publique). Si c'est votre cas, rendez-vous sur notre
|
||||
<a href=%{contact_path}>formulaire de contact public</a>.</p>"
|
||||
<a href=\"%{contact_path}\">formulaire de contact public</a>.</p>"
|
||||
contact_team: Contactez notre équipe
|
||||
pro_phone_number: Numéro de téléphone professionnel (ligne directe)
|
||||
pro_mail: Adresse e-mail professionnelle
|
||||
|
|
5
db/migrate/20230126145329_add_reminded_at_to_avis.rb
Normal file
5
db/migrate/20230126145329_add_reminded_at_to_avis.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddRemindedAtToAvis < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :avis, :reminded_at, :datetime
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2023_01_17_094317) do
|
||||
ActiveRecord::Schema.define(version: 2023_01_26_145329) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pgcrypto"
|
||||
|
@ -164,6 +164,7 @@ ActiveRecord::Schema.define(version: 2023_01_17_094317) do
|
|||
t.text "introduction"
|
||||
t.datetime "revoked_at"
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "reminded_at"
|
||||
t.index ["claimant_id"], name: "index_avis_on_claimant_id"
|
||||
t.index ["dossier_id"], name: "index_avis_on_dossier_id"
|
||||
t.index ["experts_procedure_id"], name: "index_avis_on_experts_procedure_id"
|
||||
|
|
|
@ -32,25 +32,10 @@ namespace :benchmarks do
|
|||
|
||||
desc 'Attestation Template parser'
|
||||
task attestation_template_parser: :environment do
|
||||
progress = ProgressReport.new(AttestationTemplate.count)
|
||||
AttestationTemplate.find_each do |template|
|
||||
parsed = TagsSubstitutionConcern::TagsParser.parse(template.body)
|
||||
serialized = parsed.map do |token|
|
||||
case token
|
||||
in { tag: tag }
|
||||
"--#{tag}--"
|
||||
in { text: text }
|
||||
text
|
||||
procedure = Procedure.find(68139)
|
||||
Benchmark.bm do |x|
|
||||
x.report("Empty") { TagsSubstitutionConcern::TagsParser.parse('') }
|
||||
x.report("Démarche 68139") { TagsSubstitutionConcern::TagsParser.parse(procedure.attestation_template.body) }
|
||||
end
|
||||
end.join('')
|
||||
if serialized != template.body
|
||||
throw "Template '#{serialized}' is not eq '#{template.body}' with attestation template #{template.id}"
|
||||
end
|
||||
progress.inc
|
||||
rescue => e
|
||||
pp "Error with attestation template #{template.id}"
|
||||
throw e
|
||||
end
|
||||
progress.finish
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
namespace :after_party do
|
||||
desc 'Deployment task: fix_dossier_transfer_with_uppercase'
|
||||
task fix_dossier_transfer_with_uppercase: :environment do
|
||||
puts "Running deploy task 'fix_dossier_transfer_with_uppercase'"
|
||||
# in production, about 1000, no need to track progress
|
||||
|
||||
DossierTransfer.all.find_each do |dt|
|
||||
if /A-Z/.match?(dt.email)
|
||||
dt.email = dt.email.downcase
|
||||
dt.save
|
||||
end
|
||||
end
|
||||
# Put your task implementation HERE.
|
||||
|
||||
# Update task as completed. If you remove the line below, the task will
|
||||
# run with every deploy (or every time you call after_party:run).
|
||||
AfterParty::TaskRecord
|
||||
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||
end
|
||||
end
|
|
@ -865,6 +865,10 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
}
|
||||
end
|
||||
|
||||
before do
|
||||
allow(PiecesJustificativesService).to receive(:generate_dossier_export).with([dossier], include_infos_administration: true).and_call_original
|
||||
end
|
||||
|
||||
it 'includes an attachment' do
|
||||
expect(subject.headers['Content-Disposition']).to start_with('attachment; ')
|
||||
end
|
||||
|
|
|
@ -26,6 +26,11 @@ describe Users::TransfersController, type: :controller do
|
|||
it { expect(DossierTransfer.last.dossiers).to eq([dossier]) }
|
||||
end
|
||||
|
||||
context 'with upper case email' do
|
||||
let(:email) { "Test@rspec.net" }
|
||||
it { expect(DossierTransfer.last.email).to eq(email.strip.downcase) }
|
||||
end
|
||||
|
||||
shared_examples 'email error' do
|
||||
it { expect { subject }.not_to change { DossierTransfer.count } }
|
||||
it { expect(flash.alert).to match([/invalide/]) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
describe ActiveStorage::DownloadableFile do
|
||||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
|
||||
subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id)) }
|
||||
subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossiers(Dossier.where(id: dossier.id), with_bills: true, with_champs_private: true) }
|
||||
|
||||
describe 'create_list_from_dossiers' do
|
||||
context 'when no piece_justificative is present' do
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
describe Champs::DateChamp do
|
||||
let(:date_champ) { build(:champ_date) }
|
||||
let(:date_champ) { create(:champ_date) }
|
||||
|
||||
describe '#convert_to_iso8601' do
|
||||
it 'preserves nil' do
|
||||
|
@ -37,6 +37,12 @@ describe Champs::DateChamp do
|
|||
champ.save
|
||||
expect(champ.reload.value).to eq("2023-12-21")
|
||||
end
|
||||
|
||||
it 'converts to nil if false iso' do
|
||||
champ = champ_with_value("2023-27-02")
|
||||
champ.save
|
||||
expect(champ.reload.value).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
def champ_with_value(number)
|
||||
|
|
|
@ -516,7 +516,7 @@ describe TagsSubstitutionConcern, type: :model do
|
|||
|
||||
describe 'parser' do
|
||||
it do
|
||||
tokens = TagsSubstitutionConcern::TagsParser.parse("hello world --public--, --numéro du dossier--, un test--yolo-- encore du text\n---\n encore du text")
|
||||
tokens = TagsSubstitutionConcern::TagsParser.parse("hello world --public--, --numéro du dossier--, un test--yolo-- encore du text\n---\n encore du text --- et encore du text\n--tag--")
|
||||
expect(tokens).to eq([
|
||||
{ text: "hello world " },
|
||||
{ tag: "public" },
|
||||
|
@ -524,14 +524,15 @@ describe TagsSubstitutionConcern, type: :model do
|
|||
{ tag: "numéro du dossier" },
|
||||
{ text: ", un test" },
|
||||
{ tag: "yolo" },
|
||||
{ text: " encore du text\n" + "---\n" + " encore du text" }
|
||||
{ text: " encore du text\n" + "---\n" + " encore du text --- et encore du text\n" },
|
||||
{ tag: "tag" }
|
||||
])
|
||||
end
|
||||
|
||||
it 'allow for - before tag' do
|
||||
tokens = TagsSubstitutionConcern::TagsParser.parse("hello --yolo-- -- before-- --after -- -- around -- world ---numéro-du - dossier--")
|
||||
tokens = TagsSubstitutionConcern::TagsParser.parse("-----------------\nhello --yolo-- -- before-- --after -- -- around -- world ---numéro-du - dossier--")
|
||||
expect(tokens).to eq([
|
||||
{ text: "hello " },
|
||||
{ text: "-----------------\nhello " },
|
||||
{ tag: "yolo" },
|
||||
{ text: " " },
|
||||
{ tag: "before" },
|
||||
|
|
|
@ -239,7 +239,7 @@ describe Dossier do
|
|||
end
|
||||
|
||||
describe "#rebase" do
|
||||
let(:procedure) { create(:procedure, :with_type_de_champ_mandatory, :with_yes_no, :with_repetition, :with_datetime) }
|
||||
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :text, mandatory: true }, { type: :repetition, children: [{ type: :text }] }, { type: :datetime }, { type: :yes_no }, { type: :integer_number }]) }
|
||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||
|
||||
let(:yes_no_type_de_champ) { procedure.active_revision.types_de_champ_public.find { |tdc| tdc.type_champ == TypeDeChamp.type_champs.fetch(:yes_no) } }
|
||||
|
@ -248,6 +248,8 @@ describe Dossier do
|
|||
let(:text_champ) { dossier.champs_public.find(&:mandatory?) }
|
||||
let(:rebased_text_champ) { dossier.champs_public.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:text) } }
|
||||
|
||||
let(:rebased_number_champ) { dossier.champs_public.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:integer_number) } }
|
||||
|
||||
let(:datetime_type_de_champ) { procedure.active_revision.types_de_champ_public.find { |tdc| tdc.type_champ == TypeDeChamp.type_champs.fetch(:datetime) } }
|
||||
let(:datetime_champ) { dossier.champs_public.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:datetime) } }
|
||||
let(:rebased_datetime_champ) { dossier.champs_public.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:date) } }
|
||||
|
@ -287,7 +289,7 @@ describe Dossier do
|
|||
libelle = text_type_de_champ.libelle
|
||||
|
||||
expect(dossier.revision).to eq(procedure.published_revision)
|
||||
expect(dossier.champs_public.size).to eq(4)
|
||||
expect(dossier.champs_public.size).to eq(5)
|
||||
expect(repetition_champ.rows.size).to eq(2)
|
||||
expect(repetition_champ.rows[0].size).to eq(1)
|
||||
expect(repetition_champ.rows[1].size).to eq(1)
|
||||
|
@ -299,7 +301,7 @@ describe Dossier do
|
|||
|
||||
expect(procedure.revisions.size).to eq(3)
|
||||
expect(dossier.revision).to eq(procedure.published_revision)
|
||||
expect(dossier.champs_public.size).to eq(4)
|
||||
expect(dossier.champs_public.size).to eq(5)
|
||||
expect(rebased_text_champ.value).to eq(text_champ.value)
|
||||
expect(rebased_text_champ.type_de_champ_id).not_to eq(text_champ.type_de_champ_id)
|
||||
expect(rebased_datetime_champ.type_champ).to eq(TypeDeChamp.type_champs.fetch(:date))
|
||||
|
@ -309,6 +311,7 @@ describe Dossier do
|
|||
expect(rebased_repetition_champ.rows[1].size).to eq(2)
|
||||
expect(rebased_text_champ.rebased_at).not_to be_nil
|
||||
expect(rebased_datetime_champ.rebased_at).not_to be_nil
|
||||
expect(rebased_number_champ.rebased_at).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1405,6 +1405,46 @@ describe Dossier do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#geo_data' do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) }
|
||||
let(:geo_area) { create(:geo_area) }
|
||||
let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) }
|
||||
|
||||
context "without data" do
|
||||
it { expect(dossier.geo_data?).to be_falsey }
|
||||
end
|
||||
|
||||
context "with geo data in public champ" do
|
||||
before do
|
||||
dossier.champs_public << champ_carte
|
||||
end
|
||||
|
||||
it { expect(dossier.geo_data?).to be_truthy }
|
||||
end
|
||||
|
||||
context "with geo data in private champ" do
|
||||
before do
|
||||
dossier.champs_private << champ_carte
|
||||
end
|
||||
|
||||
it { expect(dossier.geo_data?).to be_truthy }
|
||||
end
|
||||
|
||||
it "should solve N+1 problem" do
|
||||
dossier.champs_public << create_list(:champ_carte, 3, type_de_champ: type_de_champ_carte, geo_areas: [create(:geo_area)])
|
||||
|
||||
count = 0
|
||||
|
||||
callback = lambda { |*_args| count += 1 }
|
||||
ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
|
||||
dossier.geo_data?
|
||||
end
|
||||
|
||||
expect(count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'dossier_operation_log after dossier deletion' do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:dossier_operation_log) { create(:dossier_operation_log, dossier: dossier) }
|
||||
|
@ -1853,6 +1893,19 @@ describe Dossier do
|
|||
before { dossier.champs_public << champ_piece_justificative }
|
||||
it { expect(Champs::PieceJustificativeChamp.where(dossier: new_dossier).first.piece_justificative_file.first.blob).to eq(champ_piece_justificative.piece_justificative_file.first.blob) }
|
||||
end
|
||||
|
||||
context 'for Champs::AddressChamp, original_champ.data is duped' do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:type_de_champs_adress) { create(:type_de_champ_address, procedure: dossier.procedure) }
|
||||
let(:etablissement) { create(:etablissement) }
|
||||
let(:champ_address) { create(:champ_address, type_de_champ: type_de_champs_adress, external_id: 'Address', data: { city_code: '75019' }) }
|
||||
before { dossier.champs_public << champ_address }
|
||||
|
||||
it { expect(Champs::AddressChamp.where(dossier: dossier).first.data).not_to be_nil }
|
||||
it { expect(Champs::AddressChamp.where(dossier: dossier).first.external_id).not_to be_nil }
|
||||
it { expect(Champs::AddressChamp.where(dossier: new_dossier).first.external_id).to eq(champ_address.external_id) }
|
||||
it { expect(Champs::AddressChamp.where(dossier: new_dossier).first.data).to eq(champ_address.data) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'private are renewd' do
|
||||
|
|
|
@ -854,4 +854,15 @@ describe ProcedurePresentation do
|
|||
it { is_expected.to eq(sorted_ids) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#field_enum' do
|
||||
context "field is groupe_instructeur" do
|
||||
let!(:gi_2) { instructeur.groupe_instructeurs.create(label: 'gi2', procedure:) }
|
||||
let!(:gi_3) { instructeur.groupe_instructeurs.create(label: 'gi3', procedure: create(:procedure)) }
|
||||
|
||||
subject { procedure_presentation.field_enum('groupe_instructeur/id') }
|
||||
|
||||
it { is_expected.to eq([['défaut', procedure.defaut_groupe_instructeur.id], ['gi2', gi_2.id]]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -872,4 +872,21 @@ describe ProcedureRevision do
|
|||
it { expect(draft.dependent_conditions(first_champ)).to eq([second_champ]) }
|
||||
it { expect(draft.dependent_conditions(second_champ)).to eq([]) }
|
||||
end
|
||||
|
||||
describe 'only_present_on_draft?' do
|
||||
let(:procedure) { create(:procedure, types_de_champ_public: [{ libelle: 'Un champ texte' }]) }
|
||||
let(:type_de_champ) { procedure.draft_revision.types_de_champ_public.first }
|
||||
|
||||
it {
|
||||
expect(type_de_champ.only_present_on_draft?).to be_truthy
|
||||
procedure.publish!
|
||||
expect(type_de_champ.only_present_on_draft?).to be_falsey
|
||||
procedure.draft_revision.remove_type_de_champ(type_de_champ.stable_id)
|
||||
expect(type_de_champ.only_present_on_draft?).to be_falsey
|
||||
expect(type_de_champ.revisions.count).to eq(1)
|
||||
procedure.publish_revision!
|
||||
expect(type_de_champ.only_present_on_draft?).to be_falsey
|
||||
expect(type_de_champ.revisions.count).to eq(1)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
describe PiecesJustificativesService do
|
||||
describe '.liste_documents' do
|
||||
let(:for_expert) { false }
|
||||
let(:with_champs_private) { true }
|
||||
let(:with_bills) { true }
|
||||
|
||||
subject do
|
||||
PiecesJustificativesService
|
||||
.liste_documents(Dossier.where(id: dossier.id), for_expert)
|
||||
.liste_documents(Dossier.where(id: dossier.id), with_bills:, with_champs_private:)
|
||||
.map(&:first)
|
||||
end
|
||||
|
||||
|
@ -59,8 +60,8 @@ describe PiecesJustificativesService do
|
|||
|
||||
it { expect(subject).to match_array(private_pj_champ.call(dossier).piece_justificative_file.attachments) }
|
||||
|
||||
context 'for expert' do
|
||||
let(:for_expert) { true }
|
||||
context 'without private champ' do
|
||||
let(:with_champs_private) { false }
|
||||
|
||||
it { expect(subject).to be_empty }
|
||||
end
|
||||
|
@ -171,8 +172,8 @@ describe PiecesJustificativesService do
|
|||
expect(subject).to match_array([dossier_bs.serialized.attachment, dossier_bs.signature.attachment])
|
||||
end
|
||||
|
||||
context 'for expert' do
|
||||
let(:for_expert) { true }
|
||||
context 'without bills' do
|
||||
let(:with_bills) { false }
|
||||
|
||||
it { expect(subject).to be_empty }
|
||||
end
|
||||
|
@ -192,8 +193,8 @@ describe PiecesJustificativesService do
|
|||
|
||||
it { expect(subject).to match_array(dol.serialized.attachment) }
|
||||
|
||||
context 'for expert' do
|
||||
let(:for_expert) { true }
|
||||
context 'without bills' do
|
||||
let(:with_bills) { false }
|
||||
|
||||
it { expect(subject).to be_empty }
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ describe 'As an administrateur I wanna clone a procedure', js: true do
|
|||
scenario do
|
||||
visit admin_procedures_path
|
||||
expect(page.find_by_id('procedures')['data-item-count']).to eq('1')
|
||||
page.all('.procedures-actions-btn').first.click
|
||||
page.all('.admin-procedures-list-row .dropdown .fr-btn').first.click
|
||||
page.all('.clone-btn').first.click
|
||||
visit admin_procedures_path(statut: "brouillons")
|
||||
expect(page.find_by_id('procedures')['data-item-count']).to eq('1')
|
||||
|
|
|
@ -116,7 +116,6 @@ describe 'Inviting an expert:' do
|
|||
click_on '1 avis à donner'
|
||||
click_on avis.dossier.user.email
|
||||
|
||||
find(:css, '[aria-controls=print-pj-menu]').click
|
||||
click_on 'Télécharger le dossier et toutes ses pièces jointes'
|
||||
# For some reason, clicking the download link does not trigger the download in the headless browser ;
|
||||
# So we need to go to the download link directly
|
||||
|
|
|
@ -26,6 +26,21 @@ describe 'dropdown list with other option activated', js: true do
|
|||
find('.radios').find('label:last-child').find('input').select_option
|
||||
expect(page).to have_selector('.drop_down_other', visible: true)
|
||||
end
|
||||
|
||||
scenario "Getting back from other save the new option", js: true do
|
||||
fill_individual
|
||||
|
||||
choose "Autre"
|
||||
fill_in("Veuillez saisir votre autre choix", with: "My choice")
|
||||
|
||||
wait_until { user_dossier.champs_public.first.value == "My choice" }
|
||||
expect(user_dossier.champs_public.first.value).to eq("My choice")
|
||||
|
||||
choose "Secondary 1.1"
|
||||
|
||||
wait_until { user_dossier.champs_public.first.value == "Secondary 1.1" }
|
||||
expect(user_dossier.champs_public.first.value).to eq("Secondary 1.1")
|
||||
end
|
||||
end
|
||||
|
||||
context 'with select' do
|
||||
|
|
|
@ -27,7 +27,7 @@ describe 'users/dossiers/show/header.html.haml', type: :view do
|
|||
end
|
||||
|
||||
it 'can download the dossier' do
|
||||
expect(rendered).to have_text("Tout le dossier")
|
||||
expect(rendered).to have_selector('a[title="Tout le dossier"]')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -45,7 +45,7 @@ describe 'users/dossiers/show/header.html.haml', type: :view do
|
|||
end
|
||||
|
||||
it 'can download the dossier' do
|
||||
expect(rendered).to have_text("Tout le dossier")
|
||||
expect(rendered).to have_selector('a[title="Tout le dossier"]')
|
||||
end
|
||||
|
||||
it 'does not display a new procedure link' do
|
||||
|
@ -68,7 +68,7 @@ describe 'users/dossiers/show/header.html.haml', type: :view do
|
|||
end
|
||||
|
||||
it 'can download the dossier' do
|
||||
expect(rendered).to have_text("Tout le dossier")
|
||||
expect(rendered).to have_selector('a[title="Tout le dossier"]')
|
||||
end
|
||||
|
||||
it 'displays a new procedure link' do
|
||||
|
@ -105,7 +105,7 @@ describe 'users/dossiers/show/header.html.haml', type: :view do
|
|||
end
|
||||
|
||||
it 'can download the dossier' do
|
||||
expect(rendered).to have_text("Tout le dossier")
|
||||
expect(rendered).to have_selector('a[title="Tout le dossier"]')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -124,7 +124,7 @@ describe 'users/dossiers/show/header.html.haml', type: :view do
|
|||
end
|
||||
|
||||
it 'can not download the dossier' do
|
||||
expect(rendered).not_to have_text("Tout le dossier")
|
||||
expect(rendered).not_to have_selector('a[title="Tout le dossier"]')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue