Merge branch 'demarches-simplifiees:main' into poc-self_hosted_runners
This commit is contained in:
commit
258c7657c8
161 changed files with 2661 additions and 1196 deletions
|
@ -20,7 +20,8 @@ module.exports = {
|
|||
'prettier/prettier': 'error',
|
||||
'react-hooks/rules-of-hooks': 'error',
|
||||
'react-hooks/exhaustive-deps': 'error',
|
||||
'react/prop-types': 'off'
|
||||
'react/prop-types': 'off',
|
||||
'react/no-deprecated': 'off'
|
||||
},
|
||||
settings: {
|
||||
react: { version: 'detect' }
|
||||
|
|
|
@ -1 +1 @@
|
|||
16.14.0
|
||||
18.17.0
|
||||
|
|
153
Gemfile.lock
153
Gemfile.lock
|
@ -4,47 +4,47 @@ GEM
|
|||
aasm (5.2.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
acsv (0.0.1)
|
||||
actioncable (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
actioncable (7.0.7.2)
|
||||
actionpack (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activejob (= 7.0.5.1)
|
||||
activerecord (= 7.0.5.1)
|
||||
activestorage (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
actionmailbox (7.0.7.2)
|
||||
actionpack (= 7.0.7.2)
|
||||
activejob (= 7.0.7.2)
|
||||
activerecord (= 7.0.7.2)
|
||||
activestorage (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
actionview (= 7.0.5.1)
|
||||
activejob (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
actionmailer (7.0.7.2)
|
||||
actionpack (= 7.0.7.2)
|
||||
actionview (= 7.0.7.2)
|
||||
activejob (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (7.0.5.1)
|
||||
actionview (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
actionpack (7.0.7.2)
|
||||
actionview (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
rack (~> 2.0, >= 2.2.4)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activerecord (= 7.0.5.1)
|
||||
activestorage (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
actiontext (7.0.7.2)
|
||||
actionpack (= 7.0.7.2)
|
||||
activerecord (= 7.0.7.2)
|
||||
activestorage (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
actionview (7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
|
@ -62,26 +62,26 @@ GEM
|
|||
activemodel (>= 5.2.0)
|
||||
activestorage (>= 5.2.0)
|
||||
activesupport (>= 5.2.0)
|
||||
activejob (7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
activejob (7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
activerecord (7.0.5.1)
|
||||
activemodel (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
activestorage (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activejob (= 7.0.5.1)
|
||||
activerecord (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
activemodel (7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
activerecord (7.0.7.2)
|
||||
activemodel (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
activestorage (7.0.7.2)
|
||||
actionpack (= 7.0.7.2)
|
||||
activejob (= 7.0.7.2)
|
||||
activerecord (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activestorage-openstack (1.5.1)
|
||||
fog-openstack (~> 1.0)
|
||||
activestorage-openstack (1.6.0)
|
||||
fog-openstack (>= 1.0.9)
|
||||
marcel
|
||||
rails (>= 5.2.2)
|
||||
activesupport (7.0.5.1)
|
||||
activesupport (7.0.7.2)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
|
@ -236,7 +236,7 @@ GEM
|
|||
tzinfo
|
||||
ethon (0.15.0)
|
||||
ffi (>= 1.15.0)
|
||||
excon (0.79.0)
|
||||
excon (0.102.0)
|
||||
factory_bot (6.1.0)
|
||||
activesupport (>= 5.0.0)
|
||||
ffi (1.15.5)
|
||||
|
@ -254,26 +254,25 @@ GEM
|
|||
rack (>= 1.4, < 3)
|
||||
rack-protection (>= 1.5.3, <= 4.0.0)
|
||||
sanitize (< 7)
|
||||
fog-core (2.2.3)
|
||||
fog-core (2.3.0)
|
||||
builder
|
||||
excon (~> 0.71)
|
||||
formatador (~> 0.2)
|
||||
formatador (>= 0.2, < 2.0)
|
||||
mime-types
|
||||
fog-json (1.2.0)
|
||||
fog-core
|
||||
multi_json (~> 1.10)
|
||||
fog-openstack (1.0.11)
|
||||
fog-openstack (1.1.0)
|
||||
fog-core (~> 2.1)
|
||||
fog-json (>= 1.0)
|
||||
ipaddress (>= 0.8)
|
||||
formatador (0.2.5)
|
||||
formatador (1.1.0)
|
||||
fugit (1.4.2)
|
||||
et-orbi (~> 1.1, >= 1.1.8)
|
||||
raabro (~> 1.4)
|
||||
geo_coord (0.2.0)
|
||||
geocoder (1.6.5)
|
||||
globalid (1.1.0)
|
||||
activesupport (>= 5.0)
|
||||
globalid (1.2.1)
|
||||
activesupport (>= 6.1)
|
||||
gon (6.4.0)
|
||||
actionpack (>= 3.0.20)
|
||||
i18n (>= 0.7)
|
||||
|
@ -349,7 +348,6 @@ GEM
|
|||
ruby-vips (>= 2.0.17, < 3)
|
||||
invisible_captcha (2.0.0)
|
||||
rails (>= 5.0)
|
||||
ipaddress (0.8.3)
|
||||
jquery-rails (4.5.1)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
|
@ -386,7 +384,7 @@ GEM
|
|||
actionmailer (>= 3.2)
|
||||
letter_opener (~> 1.0)
|
||||
railties (>= 3.2)
|
||||
listen (3.4.1)
|
||||
listen (3.8.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
llhttp-ffi (0.4.0)
|
||||
|
@ -414,21 +412,21 @@ GEM
|
|||
matrix (0.4.2)
|
||||
memory_profiler (1.0.0)
|
||||
method_source (1.0.0)
|
||||
mime-types (3.3.1)
|
||||
mime-types (3.5.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2021.0212)
|
||||
mime-types-data (3.2023.0808)
|
||||
mina (1.2.4)
|
||||
open4 (~> 1.3.4)
|
||||
rake
|
||||
mini_magick (4.11.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.4)
|
||||
minitest (5.18.1)
|
||||
minitest (5.20.0)
|
||||
msgpack (1.4.2)
|
||||
multi_json (1.15.0)
|
||||
mustermann (3.0.0)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
net-imap (0.3.6)
|
||||
net-imap (0.3.7)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
|
@ -439,7 +437,7 @@ GEM
|
|||
net-protocol
|
||||
netrc (0.11.0)
|
||||
nio4r (2.5.9)
|
||||
nokogiri (1.15.3)
|
||||
nokogiri (1.15.4)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
open4 (1.3.4)
|
||||
|
@ -493,7 +491,7 @@ GEM
|
|||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.7.1)
|
||||
rack (2.2.7)
|
||||
rack (2.2.8)
|
||||
rack-attack (6.5.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-mini-profiler (3.0.0)
|
||||
|
@ -513,26 +511,27 @@ GEM
|
|||
rack_session_access (0.2.0)
|
||||
builder (>= 2.0.0)
|
||||
rack (>= 1.0.0)
|
||||
rails (7.0.5.1)
|
||||
actioncable (= 7.0.5.1)
|
||||
actionmailbox (= 7.0.5.1)
|
||||
actionmailer (= 7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
actiontext (= 7.0.5.1)
|
||||
actionview (= 7.0.5.1)
|
||||
activejob (= 7.0.5.1)
|
||||
activemodel (= 7.0.5.1)
|
||||
activerecord (= 7.0.5.1)
|
||||
activestorage (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
rails (7.0.7.2)
|
||||
actioncable (= 7.0.7.2)
|
||||
actionmailbox (= 7.0.7.2)
|
||||
actionmailer (= 7.0.7.2)
|
||||
actionpack (= 7.0.7.2)
|
||||
actiontext (= 7.0.7.2)
|
||||
actionview (= 7.0.7.2)
|
||||
activejob (= 7.0.7.2)
|
||||
activemodel (= 7.0.7.2)
|
||||
activerecord (= 7.0.7.2)
|
||||
activestorage (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.0.5.1)
|
||||
railties (= 7.0.7.2)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
activesupport (>= 5.0.1.rc1)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
rails-dom-testing (2.2.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
rails-erd (1.6.1)
|
||||
activerecord (>= 4.2)
|
||||
|
@ -545,9 +544,9 @@ GEM
|
|||
rails-i18n (7.0.3)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
railties (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
railties (7.0.7.2)
|
||||
actionpack (= 7.0.7.2)
|
||||
activesupport (= 7.0.7.2)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
|
@ -555,7 +554,7 @@ GEM
|
|||
rainbow (3.1.1)
|
||||
rake (13.0.6)
|
||||
rake-progressbar (0.0.5)
|
||||
rb-fsevent (0.10.4)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
redcarpet (3.6.0)
|
||||
|
@ -777,7 +776,7 @@ GEM
|
|||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
websocket (1.2.9)
|
||||
websocket-driver (0.7.5)
|
||||
websocket-driver (0.7.6)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
xmlenc (0.8.0)
|
||||
|
@ -789,7 +788,7 @@ GEM
|
|||
nokogiri (~> 1.11)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.6.8)
|
||||
zeitwerk (2.6.11)
|
||||
zip_tricks (5.6.0)
|
||||
zipline (1.4.1)
|
||||
actionpack (>= 6.0, < 8.0)
|
||||
|
|
|
@ -310,24 +310,6 @@ ul.dropdown-items {
|
|||
width: 340px;
|
||||
}
|
||||
|
||||
label {
|
||||
width: 100px;
|
||||
display: inline-block;
|
||||
margin-bottom: 2 * $default-spacer;
|
||||
}
|
||||
|
||||
input:not(.fr-btn),
|
||||
select {
|
||||
width: 200px;
|
||||
display: inline-block;
|
||||
background-color: $light-grey;
|
||||
border: 1px solid $border-grey;
|
||||
}
|
||||
|
||||
[disabled] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,21 @@ fieldset {
|
|||
width: max-content;
|
||||
}
|
||||
|
||||
button.fr-tag-bug {
|
||||
background-color: $blue-france-500;
|
||||
color: #FFFFFF;
|
||||
|
||||
&:hover {
|
||||
background-color: #1212FF;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.tag-dismiss {
|
||||
font-size: 1rem;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
// on veut ferrer à droite le dropdown de sélecteur de langue
|
||||
@media (min-width: 62em) {
|
||||
.fr-nav__item.custom-fr-translate-flex-end {
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
.fr-input-group {
|
||||
.fr-input-group,
|
||||
.fr-select-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
|
@ -116,16 +117,8 @@
|
|||
visibility: visible;
|
||||
}
|
||||
|
||||
// Move checkbox to the top-left side of the label
|
||||
&.editable-champ-checkbox {
|
||||
label.admin-default-zone {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
&.editable-champ-checkbox {
|
||||
label {
|
||||
padding-left: 28px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
@ -210,18 +203,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
.fr-label {
|
||||
.fr-label .fr-hint-text > *,
|
||||
.fr-fieldset__legend .fr-hint-text > * {
|
||||
// la description d'un champ peut contenir du markup (markdown->html),
|
||||
// on herite donc la fontsize/mrgin/padding du fr-hint-text
|
||||
.fr-hint-text > * {
|
||||
font-size: inherit;
|
||||
margin: inherit;
|
||||
padding: inherit;
|
||||
}
|
||||
font-size: inherit;
|
||||
margin: inherit;
|
||||
padding: inherit;
|
||||
}
|
||||
|
||||
input[type=password],
|
||||
select {
|
||||
select:not(.fr-select) {
|
||||
display: block;
|
||||
margin-bottom: 0;
|
||||
|
||||
|
@ -246,9 +238,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
input[type=text]:not([data-address='true']),
|
||||
select {
|
||||
border-radius: 4px;
|
||||
input[type=text]:not([data-address='true']) {
|
||||
border: solid 1px $border-grey;
|
||||
padding: $default-padding;
|
||||
|
||||
|
@ -524,7 +514,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
fieldset ~ .spinner {
|
||||
fieldset + .spinner {
|
||||
position: relative;
|
||||
top: -($default-fields-spacer / 2);
|
||||
}
|
||||
|
|
|
@ -14,13 +14,18 @@
|
|||
|
||||
.type-de-champ {
|
||||
width: 100%;
|
||||
background-color: #FAFDFF;
|
||||
border: 1px solid $border-grey;
|
||||
border-radius: 5px;
|
||||
margin-bottom: $default-padding * 2;
|
||||
box-shadow: 0px 2px 4px -4px;
|
||||
margin-bottom: $default-padding;
|
||||
overflow: hidden;
|
||||
|
||||
.type-de-champ-container {
|
||||
width: 100%;
|
||||
background-color: #FAFDFF;
|
||||
border: 1px solid $border-grey;
|
||||
border-radius: 5px;
|
||||
margin-bottom: $default-padding;
|
||||
box-shadow: 0px 2px 4px -4px;
|
||||
}
|
||||
|
||||
.handle.icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
@ -71,6 +76,10 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
&.last .type-de-champ-add-button.root {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.head {
|
||||
background-color: #FAFDFF;
|
||||
|
||||
|
@ -91,10 +100,6 @@
|
|||
&.section {
|
||||
padding: $default-spacer $default-spacer 0;
|
||||
margin-bottom: 8px;
|
||||
|
||||
input {
|
||||
background-color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
&.hr {
|
||||
|
|
|
@ -2,13 +2,6 @@ class ApplicationComponent < ViewComponent::Base
|
|||
include ViewComponent::Translatable
|
||||
include FlipperHelper
|
||||
|
||||
# Takes a Hash of { class_name: boolean }.
|
||||
# Returns truthy class names in an array. Array can be passed as-it in rails helpers,
|
||||
# and is still manipulable if needed.
|
||||
def class_names(class_names)
|
||||
class_names.filter { _2 }.keys
|
||||
end
|
||||
|
||||
def current_user
|
||||
controller.current_user
|
||||
end
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
= form_tag add_filter_instructeur_procedure_path(procedure), method: :post, class: 'dropdown-form large', id: 'filter-component', data: { turbo: true, controller: 'autosubmit' } do
|
||||
= label_tag :field, t('.column')
|
||||
= select_tag :field, options_for_select(filterable_fields_for_select, field_id), include_blank: field_id.nil?
|
||||
%input.hidden{ type: 'submit', formaction: update_filter_instructeur_procedure_path(procedure), data: { autosubmit_target: 'submitter' } }
|
||||
%br
|
||||
= label_tag :value, t('.value'), for: 'value'
|
||||
.fr-select-group
|
||||
= label_tag :field, t('.column'), class: 'fr-label fr-m-0'
|
||||
= select_tag :field, options_for_select(filterable_fields_for_select, field_id), include_blank: field_id.nil?, class: 'fr-select'
|
||||
|
||||
%input.hidden{ type: 'submit', formaction: update_filter_instructeur_procedure_path(procedure), data: { autosubmit_target: 'submitter' } }
|
||||
|
||||
= label_tag :value, t('.value'), for: 'value', class: 'fr-label'
|
||||
- if field_type == :enum
|
||||
= select_tag :value, options_for_select(options_for_select_of_field), id: 'value', name: 'value', data: { no_autosubmit: true }
|
||||
= select_tag :value, options_for_select(options_for_select_of_field), id: 'value', name: 'value', class: 'fr-select', data: { no_autosubmit: true }
|
||||
- else
|
||||
%input#value{ type: field_type, name: :value, maxlength: ProcedurePresentation::FILTERS_VALUE_MAX_LENGTH, disabled: field_id.nil? ? true : false, data: { no_autosubmit: true } }
|
||||
%input#value.fr-input{ type: field_type, name: :value, maxlength: ProcedurePresentation::FILTERS_VALUE_MAX_LENGTH, disabled: field_id.nil? ? true : false, data: { no_autosubmit: true } }
|
||||
|
||||
= hidden_field_tag :statut, statut
|
||||
= submit_tag t('.add_filter'), class: 'fr-btn fr-btn--secondary fr-mt-2w'
|
||||
|
|
|
@ -17,6 +17,10 @@ class Dsfr::InputComponent < ApplicationComponent
|
|||
@required = required
|
||||
end
|
||||
|
||||
def dsfr_champ_container
|
||||
:div
|
||||
end
|
||||
|
||||
# add invalid class on input when input is invalid
|
||||
# and and valid on input only if another input is invalid
|
||||
def input_group_opts
|
||||
|
@ -50,6 +54,10 @@ class Dsfr::InputComponent < ApplicationComponent
|
|||
get_slot(:label).presence || default_label
|
||||
end
|
||||
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
|
||||
# kind of input helpers
|
||||
def password?
|
||||
@input_type == :password_field
|
||||
|
|
|
@ -8,6 +8,30 @@ module Dsfr
|
|||
|
||||
renders_one :hint
|
||||
|
||||
def dsfr_group_classname
|
||||
if dsfr_champ_container == :fieldset
|
||||
'fr-fieldset'
|
||||
else
|
||||
"#{dsfr_input_classname}-group"
|
||||
end
|
||||
end
|
||||
|
||||
def input_group_error_class_names
|
||||
{
|
||||
"#{dsfr_group_classname}--error" => errors_on_attribute?,
|
||||
"#{dsfr_group_classname}--valid" => !errors_on_attribute? && errors_on_another_attribute?
|
||||
}
|
||||
end
|
||||
|
||||
def errors_on_attribute?
|
||||
errors.has_key?(attribute_or_rich_body)
|
||||
end
|
||||
|
||||
# errors helpers
|
||||
def error_full_messages
|
||||
errors.full_messages_for(attribute_or_rich_body)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# lookup for edge case from `form.rich_text_area`
|
||||
|
@ -21,15 +45,14 @@ module Dsfr
|
|||
end
|
||||
end
|
||||
|
||||
def input_group_error_class_names
|
||||
{
|
||||
"fr-input-group--error": errors_on_attribute?,
|
||||
"fr-input-group--valid": !errors_on_attribute? && errors_on_another_attribute?
|
||||
}
|
||||
def fr_fieldset?
|
||||
!['fr-input', 'fr-radio', 'fr-select'].include?(dsfr_input_classname)
|
||||
end
|
||||
|
||||
def input_error_class_names
|
||||
{ 'fr-input--error': errors_on_attribute? }
|
||||
{
|
||||
"#{dsfr_input_classname}--error": errors_on_attribute?
|
||||
}
|
||||
end
|
||||
|
||||
def input_error_opts
|
||||
|
@ -70,23 +93,10 @@ module Dsfr
|
|||
@opts
|
||||
end
|
||||
|
||||
def describedby_id
|
||||
dom_id(@champ, :error_full_messages)
|
||||
end
|
||||
|
||||
def errors_on_another_attribute?
|
||||
!errors.empty?
|
||||
end
|
||||
|
||||
def errors_on_attribute?
|
||||
errors.has_key?(attribute_or_rich_body)
|
||||
end
|
||||
|
||||
# errors helpers
|
||||
def error_full_messages
|
||||
errors.full_messages_for(attribute_or_rich_body)
|
||||
end
|
||||
|
||||
def map_array_to_hash_with_true(array_or_string_or_nil)
|
||||
Array(array_or_string_or_nil).to_h { [_1, true] }
|
||||
end
|
||||
|
|
13
app/components/dsfr/input_status_message_component.rb
Normal file
13
app/components/dsfr/input_status_message_component.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
module Dsfr
|
||||
class InputStatusMessageComponent < ApplicationComponent
|
||||
def initialize(errors_on_attribute:, error_full_messages:, described_by:)
|
||||
@errors_on_attribute = errors_on_attribute
|
||||
@error_full_messages = error_full_messages
|
||||
@described_by = described_by
|
||||
end
|
||||
|
||||
def render?
|
||||
@errors_on_attribute
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
.fr-messages-group{ id: @describedby_id }
|
||||
- @error_full_messages.each do |error_message|
|
||||
%p{ class: class_names('fr-message' => true, "fr-message--#{@errors_on_attribute ? 'error' : 'valid'}" => true) }= error_message
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::AnnuaireEducationComponent < EditableChamp::ComboSearchComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
= # we do this trick because some html elements should use 'label' and some should be plain paragraphs
|
||||
|
||||
- if @champ.html_label?
|
||||
= @form.label @champ.main_value_name, id: @champ.labelledby_id, for: @champ.input_id, class: 'fr-label' do
|
||||
- render EditableChamp::ChampLabelContentComponent.new form: @form, champ: @champ, seen_at: @seen_at
|
||||
- elsif @champ.legend_label?
|
||||
%legend.fr-fieldset__legend.fr-text--regular{ id: @champ.labelledby_id }= render EditableChamp::ChampLabelContentComponent.new form: @form, champ: @champ, seen_at: @seen_at
|
||||
- elsif @champ.single_checkbox?
|
||||
-# no label to add
|
||||
- else
|
||||
.fr-label.mb-4{ id: @champ.labelledby_id }
|
||||
= render EditableChamp::ChampLabelContentComponent.new form: @form, champ: @champ, seen_at: @seen_at
|
||||
|
||||
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
class EditableChamp::CheckboxComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_champ_container
|
||||
:fieldset
|
||||
end
|
||||
|
||||
def dsfr_input_classname
|
||||
'fr-radio'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
= @form.check_box :value,
|
||||
{ required: @champ.required?, id: @champ.input_id, checked: @champ.true?, aria: { describedby: @champ.describedby_id }, class: class_names('required' => @champ.required?)},
|
||||
'true',
|
||||
'false'
|
||||
.fr-fieldset__element
|
||||
.fr-checkbox-group
|
||||
= @form.check_box :value,
|
||||
{ required: @champ.required?, id: @champ.input_id, checked: @champ.true?, aria: { describedby: @champ.describedby_id }, class: class_names('required' => @champ.required?)},
|
||||
'true',
|
||||
'false'
|
||||
%label.fr-label{ for: @champ.input_id, id: @champ.labelledby_id }
|
||||
= render EditableChamp::ChampLabelContentComponent.new form: @form, champ: @champ, seen_at: @seen_at
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
%fieldset.radios
|
||||
%legend.mandatory-explanation
|
||||
%fieldset.fr-fieldset
|
||||
%legend.fr-fieldset__legend--regular.fr-fieldset__legend
|
||||
Sélectionnez une des valeurs
|
||||
%label
|
||||
= @form.radio_button :value, Individual::GENDER_FEMALE, id: @champ.female_input_id
|
||||
= Individual.human_attribute_name('gender.female')
|
||||
|
||||
%label
|
||||
= @form.radio_button :value, Individual::GENDER_MALE, id: @champ.male_input_id
|
||||
= Individual.human_attribute_name('gender.male')
|
||||
.fr-fieldset__element.fr-fieldset__element--inline
|
||||
.fr-radio-group
|
||||
= @form.radio_button :value, Individual::GENDER_FEMALE, id: @champ.female_input_id
|
||||
%label.fr-label{ for: @champ.female_input_id }
|
||||
= Individual.human_attribute_name('gender.female')
|
||||
.fr-fieldset__element.fr-fieldset__element--inline
|
||||
.fr-radio-group
|
||||
= @form.radio_button :value, Individual::GENDER_MALE, id: @champ.male_input_id
|
||||
%label.fr-label{ for: @champ.male_input_id }
|
||||
= Individual.human_attribute_name('gender.male')
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
class EditableChamp::CommunesComponent < EditableChamp::EditableChampBaseComponent
|
||||
include ApplicationHelper
|
||||
|
||||
def dsfr_champ_container
|
||||
:fieldset
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def commune_options
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
en:
|
||||
postal_code: Enter the postal code then select the municipality from the list
|
||||
postal_code: "Enter <strong>the postal code</strong>"
|
||||
commune: "Select <strong>the municipality</strong> from the list"
|
||||
not_found: No municipality found for postal code %{postal_code}. Please check that you haven't made any mistakes.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
fr:
|
||||
postal_code: Renseignez le code postal puis sélectionnez la commune dans la liste
|
||||
postal_code: "Renseignez le <strong>code postal</strong>"
|
||||
commune: "Sélectionnez la commune dans la liste"
|
||||
not_found: Aucune commune trouvée pour le code postal %{postal_code}. Verifiez que vous n'avez pas fait d’erreur.
|
||||
|
|
|
@ -1,13 +1,23 @@
|
|||
%label.notice{ for: code_postal_input_id }= t('.postal_code')
|
||||
= @form.text_field :code_postal, required: @champ.required?, id: code_postal_input_id, class: "width-33-desktop width-100-mobile small-margin"
|
||||
- if @champ.code_postal?
|
||||
.fr-fieldset__element.fr-mb-0
|
||||
.fr-input-group
|
||||
= @form.label :code_postal, t('.postal_code').html_safe, class: 'fr-label', for: code_postal_input_id
|
||||
= @form.text_field :code_postal, required: @champ.required?, id: code_postal_input_id, class: "width-33-desktop width-100-mobile small-margin fr-input"
|
||||
- if @champ.code_postal?
|
||||
- if commune_options.empty?
|
||||
.fr-error-text.mb-4= t('.not_found', postal_code: @champ.code_postal)
|
||||
|
||||
.fr-fieldset__element.fr-mb-0
|
||||
- if commune_options.empty?
|
||||
.fr-error-text.mb-4= t('.not_found', postal_code: @champ.code_postal)
|
||||
-# noop
|
||||
- elsif commune_options.size <= 3
|
||||
%fieldset.radios
|
||||
%fieldset.fr-fieldset
|
||||
.fr-fieldset__legend--regular.fr-fieldset__legend= t('.commune').html_safe
|
||||
|
||||
- commune_options.each.with_index do |(option, value), index|
|
||||
%label
|
||||
= @form.radio_button :value, value, checked: @champ.selected == value, id: index == 0 ? @champ.input_id : nil
|
||||
= option
|
||||
.fr-fieldset__element
|
||||
.fr-radio-group
|
||||
= @form.radio_button :value, value, checked: @champ.selected == value, id: index == 0 ? @champ.input_id : "radio-#{index}-#{value.parameterize}"
|
||||
= @form.label :value, option, for: index == 0 ? @champ.input_id : "radio-#{index}-#{value.parameterize}", class: 'fr-label'
|
||||
- else
|
||||
= @form.select :value, commune_options, commune_select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile"
|
||||
= @form.label :value, t('.commune').html_safe, for: @champ.input_id, class: 'fr-label'
|
||||
= @form.select :value, commune_options, commune_select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile fr-select"
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::DateComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
class EditableChamp::DatetimeComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
|
||||
def formatted_value_for_datetime_locale
|
||||
if @champ.valid? && @champ.value.present?
|
||||
# convert to a format that the datetime-local input can understand
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::DecimalNumberComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,10 @@ class EditableChamp::DepartementsComponent < EditableChamp::EditableChampBaseCom
|
|||
|
||||
private
|
||||
|
||||
def dsfr_input_classname
|
||||
'fr-select'
|
||||
end
|
||||
|
||||
def options
|
||||
APIGeoService.departements.map { ["#{_1[:code]} – #{_1[:name]}", _1[:code]] }
|
||||
end
|
||||
|
|
|
@ -1 +1 @@
|
|||
= @form.select :value, options, select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile"
|
||||
= @form.select :value, options, select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "fr-select"
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::DgfipComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
class EditableChamp::DossierLinkComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
|
||||
def dossier
|
||||
@dossier ||= @champ.blank? ? nil : Dossier.visible_by_administration.find_by(id: @champ.to_s)
|
||||
end
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
class EditableChamp::DropDownListComponent < EditableChamp::EditableChampBaseComponent
|
||||
def select_class_names
|
||||
class_names('width-100': contains_long_option?)
|
||||
class_names('width-100': contains_long_option?, 'fr-select': true)
|
||||
end
|
||||
|
||||
def dsfr_input_classname
|
||||
'fr-select'
|
||||
end
|
||||
|
||||
def dsfr_champ_container
|
||||
@champ.render_as_radios? ? :fieldset : :div
|
||||
end
|
||||
|
||||
def contains_long_option?
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
- if @champ.options?
|
||||
- if @champ.render_as_radios?
|
||||
%fieldset.radios
|
||||
- @champ.enabled_non_empty_options.each do |option|
|
||||
%label
|
||||
= @form.radio_button :value, option
|
||||
= option
|
||||
.fr-fieldset__content
|
||||
- @champ.enabled_non_empty_options.each_with_index do |option, index|
|
||||
.fr-radio-group
|
||||
= @form.radio_button :value, option, id: "#{@champ.id}_radio_option_#{index}"
|
||||
%label.fr-label{ for: "#{@champ.id}_radio_option_#{index}" }
|
||||
= option
|
||||
|
||||
- if !@champ.mandatory?
|
||||
%label.blank-radio
|
||||
= @form.radio_button :value, '', checked: @champ.value.blank? && !@champ.other?
|
||||
Non renseigné
|
||||
.fr-radio-group
|
||||
= @form.radio_button :value, '', checked: @champ.value.blank? && !@champ.other?, id: "#{@champ.id}_radio_option_blank"
|
||||
%label.fr-label{ for: "#{@champ.id}_radio_option_blank" }
|
||||
Non renseigné
|
||||
|
||||
- if @champ.drop_down_other?
|
||||
%label
|
||||
= @form.radio_button :value, Champs::DropDownListChamp::OTHER, checked: @champ.other?
|
||||
Autre
|
||||
.fr-radio-group
|
||||
= @form.radio_button :value, Champs::DropDownListChamp::OTHER, checked: @champ.other?, id: "#{@champ.id}_radio_option_other"
|
||||
%label.fr-label{ for: "#{@champ.id}_radio_option_other" }
|
||||
Autre
|
||||
- else
|
||||
= @form.select :value, @champ.options_without_empty_value_when_mandatory(@champ.options), { selected: @champ.selected }, required: @champ.required?, id: @champ.input_id, class: select_class_names, aria: { describedby: @champ.describedby_id }
|
||||
= @form.select :value,
|
||||
@champ.options.compact_blank,
|
||||
{ selected: @champ.selected, include_blank: true },
|
||||
required: @champ.required?,
|
||||
id: @champ.input_id,
|
||||
class: select_class_names,
|
||||
aria: { describedby: @champ.describedby_id }
|
||||
|
||||
- if @champ.drop_down_other?
|
||||
= render EditableChamp::DropDownOtherInputComponent.new(form: @form, champ: @champ)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
.drop_down_other
|
||||
.notice
|
||||
%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)
|
||||
.drop_down_other.fr-mt-2w
|
||||
.fr-input-group
|
||||
%label.fr-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), class: 'fr-input'
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
class EditableChamp::EditableChampBaseComponent < ApplicationComponent
|
||||
include Dsfr::InputErrorable
|
||||
|
||||
def dsfr_champ_container
|
||||
:div
|
||||
end
|
||||
|
||||
def dsfr_input_classname
|
||||
nil
|
||||
end
|
||||
|
||||
def describedby_id
|
||||
@champ.describedby_id
|
||||
end
|
||||
|
||||
def initialize(form:, champ:, seen_at: nil, opts: {})
|
||||
@form, @champ, @seen_at, @opts = form, champ, seen_at, opts
|
||||
@attribute = :value
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
class EditableChamp::EditableChampComponent < ApplicationComponent
|
||||
include Dsfr::InputErrorable
|
||||
|
||||
def initialize(form:, champ:, seen_at: nil)
|
||||
@form, @champ, @seen_at = form, champ, seen_at
|
||||
@attribute = :value
|
||||
end
|
||||
|
||||
def champ_component
|
||||
@champ_component ||= component_class.new(form: @form, champ: @champ, seen_at: @seen_at)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def has_label?(champ)
|
||||
types_without_label = [
|
||||
TypeDeChamp.type_champs.fetch(:header_section),
|
||||
TypeDeChamp.type_champs.fetch(:explication),
|
||||
TypeDeChamp.type_champs.fetch(:repetition)
|
||||
TypeDeChamp.type_champs.fetch(:repetition),
|
||||
TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
|
||||
]
|
||||
!types_without_label.include?(@champ.type_champ)
|
||||
end
|
||||
|
@ -28,8 +31,8 @@ class EditableChamp::EditableChampComponent < ApplicationComponent
|
|||
'editable-champ': true,
|
||||
"editable-champ-#{@champ.type_champ}": true,
|
||||
"hidden": !@champ.visible?,
|
||||
"fr-input-group": true
|
||||
}.merge(input_group_error_class_names)
|
||||
champ_component.dsfr_group_classname => true
|
||||
}.merge(champ_component.input_group_error_class_names)
|
||||
),
|
||||
id: @champ.input_group_id,
|
||||
data: { controller: stimulus_controller, **data_dependent_conditions, **stimulus_values }
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
= content_tag(:div, html_options) do
|
||||
= content_tag((champ_component.dsfr_champ_container), html_options) do
|
||||
- if has_label?(@champ)
|
||||
= render EditableChamp::ChampLabelComponent.new form: @form, champ: @champ, seen_at: @seen_at
|
||||
= render component_class.new(form: @form, champ: @champ, seen_at: @seen_at)
|
||||
|
||||
- if errors_on_attribute?
|
||||
- if error_full_messages.size == 1
|
||||
%p.fr-error-text{ id: describedby_id }= error_full_messages.first
|
||||
- else
|
||||
.fr-error-text{ id: describedby_id }
|
||||
%ul.list-style-type-none.fr-pl-0
|
||||
- error_full_messages.each do |error_message|
|
||||
%li= error_message
|
||||
= render champ_component
|
||||
|
||||
= render Dsfr::InputStatusMessageComponent.new(errors_on_attribute: champ_component.errors_on_attribute?, error_full_messages: champ_component.error_full_messages, described_by: @champ.describedby_id)
|
||||
|
||||
= @form.hidden_field :id, value: @champ.id
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
class EditableChamp::EmailComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
|
||||
def email?
|
||||
true
|
||||
end
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
class EditableChamp::EpciComponent < EditableChamp::EditableChampBaseComponent
|
||||
include ApplicationHelper
|
||||
|
||||
def dsfr_champ_container
|
||||
:fieldset
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def departement_options
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
%label.notice{ for: @champ.code_departement_input_id } Le département de l’EPCI
|
||||
= @form.select :code_departement, departement_options, departement_select_options, required: @champ.required?, id: @champ.code_departement_input_id, class: "width-33-desktop width-100-mobile"
|
||||
.fr-fieldset__element
|
||||
= @form.label :code_departement, for: @champ.code_departement_input_id, class: 'fr-label' do
|
||||
- "Le département de l’EPCI"
|
||||
= @form.select :code_departement, departement_options, departement_select_options, required: @champ.required?, id: @champ.code_departement_input_id, class: "width-33-desktop width-100-mobile fr-select"
|
||||
|
||||
- if @champ.departement?
|
||||
= @form.label "EPCI", for: @champ.epci_input_id
|
||||
= @form.select :value, epci_options, epci_select_options, required: @champ.required?, id: @champ.epci_input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile"
|
||||
.fr-fieldset__element
|
||||
.fr-select-group
|
||||
= @form.label :value, for: @champ.epci_input_id, class: 'fr-label' do
|
||||
- "EPCI"
|
||||
= @form.select :value, epci_options, epci_select_options, required: @champ.required?, id: @champ.epci_input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile fr-select"
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::IbanComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::IntegerNumberComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
class EditableChamp::LinkedDropDownListComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_champ_container
|
||||
:fieldset
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def secondary_label
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
- if @champ.options?
|
||||
= @form.select :primary_value, @champ.primary_options, {}, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }
|
||||
.fr-fieldset__element.fr-mb-0
|
||||
.fr-select-group
|
||||
= render EditableChamp::ChampLabelComponent.new form: @form, champ: @champ, seen_at: @seen_at
|
||||
|
||||
= @form.select :primary_value, @champ.primary_options, {}, required: @champ.required?, class: 'fr-select fr-mb-3v', id: @champ.input_id, aria: { describedby: @champ.describedby_id }
|
||||
|
||||
- if @champ.has_secondary_options_for_primary?
|
||||
.secondary
|
||||
= @form.label :secondary_value, for: "#{@champ.input_id}-secondary" do
|
||||
- sanitize(secondary_label)
|
||||
- if @champ.drop_down_secondary_description.present?
|
||||
.notice{ id: "#{@champ.describedby_id}-secondary" }
|
||||
= render SimpleFormatComponent.new(@champ.drop_down_secondary_description, allow_a: true)
|
||||
= @form.select :secondary_value, @champ.secondary_options[@champ.primary_value], {}, required: @champ.required?, id: "#{@champ.input_id}-secondary", aria: { describedby: "#{@champ.describedby_id}-secondary" }
|
||||
.fr-fieldset__element
|
||||
.fr-select-group
|
||||
= @form.label :secondary_value, for: "#{@champ.input_id}-secondary", class: 'fr-label' do
|
||||
- sanitize(secondary_label)
|
||||
- if @champ.drop_down_secondary_description.present?
|
||||
.notice{ id: "#{@champ.describedby_id}-secondary" }
|
||||
= render SimpleFormatComponent.new(@champ.drop_down_secondary_description, allow_a: true)
|
||||
= @form.select :secondary_value, @champ.secondary_options[@champ.primary_value], {}, required: @champ.required?, class: 'fr-select', id: "#{@champ.input_id}-secondary", aria: { describedby: "#{@champ.describedby_id}-secondary" }
|
||||
- else
|
||||
= @form.hidden_field :secondary_value, value: ''
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::MesriComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
class EditableChamp::MultipleDropDownListComponent < EditableChamp::EditableChampBaseComponent
|
||||
include ApplicationHelper
|
||||
|
||||
def dsfr_input_classname
|
||||
'fr-select'
|
||||
end
|
||||
|
||||
def dsfr_champ_container
|
||||
@champ.render_as_checkboxes? ? :fieldset : :div
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
- if @champ.options?
|
||||
- if @champ.render_as_checkboxes?
|
||||
= @form.collection_check_boxes(:value, @champ.enabled_non_empty_options, :to_s, :to_s) do |b|
|
||||
- tag.div(class: 'editable-champ editable-champ-checkbox') do
|
||||
- b.label(for: @champ.checkbox_id(b.value)) do
|
||||
- b.check_box({ multiple: true, checked: @champ.selected_options.include?(b.value), aria: { describedby: @champ.describedby_id }, id: @champ.checkbox_id(b.value) }) + b.text
|
||||
= @form.collection_check_boxes :value, @champ.enabled_non_empty_options, :to_s, :to_s do |b|
|
||||
- capture do
|
||||
.fr-fieldset__element
|
||||
.fr-checkbox-group
|
||||
= b.check_box(checked: @champ.selected_options.include?(b.value), aria: { describedby: @champ.describedby_id }, id: @champ.checkbox_id(b.value), class: 'fr-checkbox-group__checkbox')
|
||||
%label.fr-label{ for: @champ.checkbox_id(b.value) }
|
||||
= b.text
|
||||
|
||||
- else
|
||||
%div{ 'data-turbo-focus-group': true }
|
||||
- if @champ.selected_options.present?
|
||||
.fr-mb-2w
|
||||
.fr-mb-2w{ "data-turbo": "true" }
|
||||
- @champ.selected_options.each do |option|
|
||||
= render NestedForms::OwnedButtonComponent.new(formaction: champs_options_path(@champ.id, option:), http_method: :delete, opt: { class: 'fr-tag fr-tag--dismiss fr-mb-1w fr-mr-1w', id: @champ.checkbox_id(option) }) do
|
||||
= render NestedForms::OwnedButtonComponent.new(formaction: champs_options_path(@champ.id, option:), http_method: :delete, opt: { aria: {pressed: true }, class: 'fr-tag fr-tag-bug fr-mb-1w fr-mr-1w', id: @champ.checkbox_id(option) }) do
|
||||
= option
|
||||
- if @champ.unselected_options.present?
|
||||
= @form.select :value, @champ.unselected_options, { selected: '', include_blank: '' }, id: @champ.input_id, aria: { describedby: @champ.describedby_id }
|
||||
= @form.select :value, @champ.unselected_options, { selected: '', include_blank: '' }, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: 'fr-select fr-mt-2v'
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::NumberComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
class EditableChamp::PaysComponent < EditableChamp::EditableChampBaseComponent
|
||||
include ApplicationHelper
|
||||
|
||||
def dsfr_input_classname
|
||||
'fr-select'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def options
|
||||
|
|
|
@ -1 +1 @@
|
|||
= @form.select :value, options, select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile"
|
||||
= @form.select :value, options, select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile fr-select"
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::PhoneComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
class EditableChamp::PieceJustificativeComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
|
||||
def view_as
|
||||
if @champ.dossier.brouillon?
|
||||
:link
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
class EditableChamp::RegionsComponent < EditableChamp::EditableChampBaseComponent
|
||||
include ApplicationHelper
|
||||
|
||||
def dsfr_input_classname
|
||||
'fr-select'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def options
|
||||
|
|
|
@ -1 +1 @@
|
|||
= @form.select :value, options, select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile"
|
||||
= @form.select :value, options, select_options, required: @champ.required?, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, class: "width-33-desktop width-100-mobile fr-select"
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::RNAComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::SiretComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
= @form.text_field(:value, input_opts(id: @champ.input_id, aria: { describedby: @champ.describedby_id }, placeholder: t(".placeholder"), data: { controller: 'turbo-input', turbo_input_load_on_connect_value: @champ.prefilled? && @champ.value.present? && @champ.etablissement.blank?, turbo_input_url_value: champs_siret_path(@champ.id) }, required: @champ.required?, pattern: "[0-9]{14}", title: t(".title"), class: "width-33-desktop", maxlength: 14))
|
||||
.spinner.right.hidden
|
||||
.siret-info{ id: dom_id(@champ, :siret_info) }
|
||||
- if @champ.etablissement.present?
|
||||
= render EditableChamp::EtablissementTitreComponent.new(etablissement: @champ.etablissement)
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::TextComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
class EditableChamp::TextareaComponent < EditableChamp::EditableChampBaseComponent
|
||||
include HtmlToStringHelper
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
class EditableChamp::TitreIdentiteComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
|
||||
def user_can_destroy?
|
||||
!@champ.mandatory? || @champ.dossier.brouillon?
|
||||
end
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
class EditableChamp::YesNoComponent < EditableChamp::EditableChampBaseComponent
|
||||
def dsfr_champ_container
|
||||
:fieldset
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
%fieldset.fr-fieldset
|
||||
%legend.fr-fieldset__legend.visually-hidden
|
||||
= t(".legend")
|
||||
|
||||
%label{ for: @champ.yes_input_id }
|
||||
.fr-fieldset__element.fr-fieldset__element--inline
|
||||
.fr-radio-group
|
||||
= @form.radio_button :value, true, id: @champ.yes_input_id
|
||||
= t(".yes")
|
||||
|
||||
%label{ for: @champ.no_input_id }
|
||||
%label.fr-label{ for: @champ.yes_input_id }
|
||||
= t(".yes")
|
||||
.fr-fieldset__element.fr-fieldset__element--inline
|
||||
.fr-radio-group
|
||||
= @form.radio_button :value, false, id: @champ.no_input_id
|
||||
= t(".no")
|
||||
%label.fr-label{ for: @champ.no_input_id }
|
||||
= t(".no")
|
||||
|
|
|
@ -26,11 +26,13 @@ class Instructeurs::SVASVRDecisionBadgeComponent < ApplicationComponent
|
|||
class_names(
|
||||
'fr-badge fr-badge--sm': true,
|
||||
'fr-badge--warning': soon?,
|
||||
'fr-badge--info': !soon?
|
||||
'fr-badge--info': !without_date? && !soon?
|
||||
)
|
||||
end
|
||||
|
||||
def soon?
|
||||
return false if object.sva_svr_decision_on.nil?
|
||||
|
||||
object.sva_svr_decision_on < 7.days.from_now.to_date
|
||||
end
|
||||
|
||||
|
@ -51,16 +53,36 @@ class Instructeurs::SVASVRDecisionBadgeComponent < ApplicationComponent
|
|||
end
|
||||
|
||||
def label_for_badge
|
||||
sva? ? "SVA :" : "SVR :"
|
||||
"#{human_decision} : "
|
||||
end
|
||||
|
||||
def title
|
||||
return if without_date?
|
||||
|
||||
if pending_correction?
|
||||
if previously_termine?
|
||||
t('.previously_termine_title')
|
||||
elsif depose_before_configuration?
|
||||
t('.depose_before_configuration_title', decision: human_decision)
|
||||
elsif without_date?
|
||||
t('.manual_decision_title', decision: human_decision)
|
||||
elsif pending_correction?
|
||||
t(".dossier_terminated_x_days_after_correction", count: days_count)
|
||||
else
|
||||
t(".dossier_terminated_on", date: helpers.l(object.sva_svr_decision_on))
|
||||
end
|
||||
end
|
||||
|
||||
def human_decision
|
||||
procedure.sva_svr_configuration.human_decision
|
||||
end
|
||||
|
||||
def previously_termine?
|
||||
return if !object.respond_to?(:previously_termine?)
|
||||
|
||||
object.previously_termine?
|
||||
end
|
||||
|
||||
def depose_before_configuration?
|
||||
return if !object.respond_to?(:sva_svr_decision_triggered_at)
|
||||
|
||||
object.sva_svr_decision_on.nil? && object.sva_svr_decision_triggered_at.nil?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
en:
|
||||
no_sva: Submitted before SVA
|
||||
no_svr: Submitted before SVR
|
||||
manual_decision: Manual instruction
|
||||
manual_decision_title: The file must be processed by an instructor, either because it was submitted before the %{decision} configuration, or because it has been returned to the instruction stage.
|
||||
depose_before_configuration: Submitted before %{decision}
|
||||
depose_before_configuration_title: This file was submitted before the %{decision} configuration.
|
||||
previously_termine_title: The file has been returned to the instruction stage. It must now be processed by an instructor.
|
||||
in_days:
|
||||
zero: Today
|
||||
one: Tomorrow
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
fr:
|
||||
no_sva: Déposé avant SVA
|
||||
no_svr: Déposé avant SVR
|
||||
manual_decision: Instruction manuelle
|
||||
manual_decision_title: Le dossier doit être traité par un instructeur, soit car il a été déposé avant la configuration %{decision}, soit car il a été repassé en instruction.
|
||||
depose_before_configuration: Déposé avant %{decision}
|
||||
depose_before_configuration_title: Ce dossier a été déposé avant la configuration %{decision}.
|
||||
previously_termine_title: Le dossier a été repassé en instruction. Il doit être traité par un instructeur.
|
||||
in_days:
|
||||
zero: Aujourd’hui
|
||||
one: Demain
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
- if without_date?
|
||||
%span.fr-badge.fr-badge--sm
|
||||
= t(sva? ? '.no_sva' : '.no_svr')
|
||||
- else
|
||||
%span{ class: classes, title: title }
|
||||
- if with_label.present?
|
||||
= label_for_badge
|
||||
- if pending_correction?
|
||||
= t('.remaining_days_after_correction', count: days_count)
|
||||
- else
|
||||
= t('.in_days', count: days_count)
|
||||
%span{ class: classes, title: title }
|
||||
- if with_label.present?
|
||||
= label_for_badge
|
||||
|
||||
- if previously_termine?
|
||||
= t('.manual_decision')
|
||||
- elsif depose_before_configuration?
|
||||
= t('.depose_before_configuration', decision: human_decision)
|
||||
- elsif without_date? # generic case without SVA/SVR date, when we have a projection
|
||||
= t('.manual_decision')
|
||||
- elsif pending_correction?
|
||||
= t('.remaining_days_after_correction', count: days_count)
|
||||
- else
|
||||
= t('.in_days', count: days_count)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to admin_procedure_administrateurs_path(@procedure), id: 'administrateurs', class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
%div
|
||||
%span.icon.accept
|
||||
%p.fr-tile-status-accept Validé
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to annotations_admin_procedure_path(@procedure), class: 'fr-tile fr-enlarge-link', title: error_messages do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if error_messages.present?
|
||||
%div
|
||||
%span.icon.refuse
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to jeton_admin_procedure_path(@procedure), class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.api_entreprise_token.present?
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to admin_procedure_api_particulier_path(@procedure), class: 'fr-tile fr-enlarge-link', id: 'api-particulier' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.api_particulier_token.present?
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to edit_admin_procedure_attestation_template_path(@procedure), class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.attestation_template&.activated?
|
||||
%div
|
||||
- if error_messages.present?
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to champs_admin_procedure_path(@procedure), class: 'fr-tile fr-enlarge-link', title: error_messages do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if error_messages.present?
|
||||
%div
|
||||
%span.icon.refuse
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to edit_admin_procedure_dossier_submitted_message_path(@procedure), class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.active_dossier_submitted_message.present?
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to admin_procedure_mail_templates_path(@procedure), class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
%div
|
||||
- if error_messages.present?
|
||||
%span.icon.refuse
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to admin_procedure_experts_path(@procedure), class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
%div
|
||||
%span.icon.preview
|
||||
%p.fr-tile-status-todo À configurer
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to admin_procedure_groupe_instructeurs_path(@procedure), id: 'groupe-instructeurs', class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.routing_enabled? || @procedure.instructeurs.present?
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to modifications_admin_procedure_path(@procedure), id: 'modifications', class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
%div
|
||||
%span.icon.accept
|
||||
%p.fr-tile-status-accept Activée
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to monavis_admin_procedure_path(@procedure), class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.monavis_embed.present?
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to edit_admin_procedure_path(@procedure), id: 'presentation', class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
%div
|
||||
%span.icon.accept
|
||||
%p.fr-tile-status-accept Validé
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to service_link, class: 'fr-tile fr-enlarge-link', id: 'service' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.service_id.present?
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to edit_admin_procedure_sva_svr_path(@procedure), class: 'fr-tile fr-enlarge-link', id: 'sva' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.sva_svr_enabled?
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.fr-col-6.fr-col-md-4.fr-col-lg-3
|
||||
= link_to zones_admin_procedure_path(@procedure), id: 'zones', class: 'fr-tile fr-enlarge-link' do
|
||||
.fr-tile__body.flex.justify-between
|
||||
.fr-tile__body.flex.column.align-center.justify-between
|
||||
- if @procedure.zones.size >= 1
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -17,6 +17,10 @@ class Procedure::OneGroupeManagementComponent < ApplicationComponent
|
|||
@groupe_instructeur.routing_rule&.right || empty
|
||||
end
|
||||
|
||||
def operator_name
|
||||
@groupe_instructeur.routing_rule&.class&.name || empty
|
||||
end
|
||||
|
||||
def targeted_champ_tag
|
||||
select_tag(
|
||||
'targeted_champ',
|
||||
|
@ -39,6 +43,21 @@ class Procedure::OneGroupeManagementComponent < ApplicationComponent
|
|||
.map { |tdc| [tdc.libelle, champ_value(tdc.stable_id).to_json] }
|
||||
end
|
||||
|
||||
def operator_tag
|
||||
select_tag('operator_name',
|
||||
options_for_select(
|
||||
options_for_operator_tag,
|
||||
selected: operator_name
|
||||
),
|
||||
class: 'fr-select')
|
||||
end
|
||||
|
||||
def options_for_operator_tag
|
||||
[Eq, NotEq]
|
||||
.map(&:name)
|
||||
.map { |name| [t(name, scope: 'logic.operators'), name] }
|
||||
end
|
||||
|
||||
def value_tag
|
||||
select_tag(
|
||||
'value',
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
.fr-mr-2w.no-wrap si le champ
|
||||
.target.fr-mr-2w
|
||||
= targeted_champ_tag
|
||||
.operator.fr-mr-2w.no-wrap est égal à
|
||||
.operator.fr-mr-2w.no-wrap
|
||||
= operator_tag
|
||||
.value
|
||||
= value_tag
|
||||
.fr-hint-text
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
class TypesDeChampEditor::AddChampButtonComponent < ApplicationComponent
|
||||
def initialize(revision:, parent: nil, is_annotation: false)
|
||||
def initialize(revision:, parent: nil, is_annotation: false, after_stable_id: nil)
|
||||
@revision = revision
|
||||
@parent = parent
|
||||
@is_annotation = is_annotation
|
||||
@after_stable_id = after_stable_id
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -25,8 +26,7 @@ class TypesDeChampEditor::AddChampButtonComponent < ApplicationComponent
|
|||
|
||||
def button_options
|
||||
{
|
||||
class: "button",
|
||||
form: { class: @parent ? "add-to-block" : "add-to-root" },
|
||||
class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-add-line",
|
||||
method: :post,
|
||||
params: {
|
||||
type_de_champ: {
|
||||
|
@ -34,7 +34,7 @@ class TypesDeChampEditor::AddChampButtonComponent < ApplicationComponent
|
|||
type_champ: TypeDeChamp.type_champs.fetch(:text),
|
||||
private: annotations? ? true : nil,
|
||||
parent_stable_id: @parent&.stable_id,
|
||||
after_stable_id: ''
|
||||
after_stable_id: @after_stable_id
|
||||
}.compact
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,7 @@ class TypesDeChampEditor::ChampComponent < ApplicationComponent
|
|||
controller: 'type-de-champ-editor',
|
||||
type_de_champ_editor_move_url_value: move_admin_procedure_type_de_champ_path(procedure, type_de_champ.stable_id),
|
||||
type_de_champ_editor_move_up_url_value: move_up_admin_procedure_type_de_champ_path(procedure, type_de_champ.stable_id),
|
||||
type_de_champ_editor_move_down_url_value: move_down_admin_procedure_type_de_champ_path(procedure, type_de_champ.stable_id),
|
||||
type_de_champ_editor_type_de_champ_stable_id_value: type_de_champ.stable_id
|
||||
type_de_champ_editor_move_down_url_value: move_down_admin_procedure_type_de_champ_path(procedure, type_de_champ.stable_id)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -1,117 +1,123 @@
|
|||
%li.type-de-champ.flex.column.justify-start{ html_options }
|
||||
.flex.justify-between.section.head.hr
|
||||
.handle.small.icon-only.icon.move-handle{ title: "Déplacer le champ vers le haut ou vers le bas" }
|
||||
.type-de-champ-container
|
||||
.flex.justify-between.section.head.hr
|
||||
.handle.small.icon-only.icon.move-handle{ title: "Déplacer le champ vers le haut ou vers le bas" }
|
||||
|
||||
- if coordinate.used_by_routing_rules?
|
||||
.flex.align-center
|
||||
%span
|
||||
utilisé pour
|
||||
= link_to('le routage', admin_procedure_groupe_instructeurs_path(revision.procedure_id, anchor: 'routing-rules'))
|
||||
- else
|
||||
.flex.justify-start.delete
|
||||
= button_to type_de_champ_path, class: 'button small icon-only danger', method: :delete, form: { data: { turbo_confirm: 'Êtes vous sûr de vouloir supprimer ce champ ?' } } do
|
||||
.icon.delete
|
||||
%span.sr-only Supprimer
|
||||
- if coordinate.used_by_routing_rules?
|
||||
.flex.align-center
|
||||
%span
|
||||
utilisé pour
|
||||
= link_to('le routage', admin_procedure_groupe_instructeurs_path(revision.procedure_id, anchor: 'routing-rules'))
|
||||
- else
|
||||
.flex.justify-start.delete
|
||||
= button_to type_de_champ_path, class: 'fr-btn fr-btn--sm fr-btn--secondary fr-icon-delete-line', title: "Supprimer le champ", method: :delete, form: { data: { turbo_confirm: 'Êtes vous sûr de vouloir supprimer ce champ ?' } } do
|
||||
.icon.delete
|
||||
%span.sr-only Supprimer
|
||||
|
||||
- if @errors.present?
|
||||
.types-de-champ-errors
|
||||
= @errors
|
||||
- if @errors.present?
|
||||
.types-de-champ-errors
|
||||
= @errors
|
||||
|
||||
.flex.justify-start.section.ml-1
|
||||
= form_for(type_de_champ, form_options) do |form|
|
||||
.flex.justify-start
|
||||
.flex.justify-start.width-33
|
||||
.flex.justify-start.column
|
||||
%button.move-up.cell.mb-1{ move_button_options(:up) }
|
||||
.icon.arrow-up.small
|
||||
%span.sr-only Déplacer le champ vers le haut
|
||||
%button.move-down.cell{ move_button_options(:down) }
|
||||
.icon.arrow-down.small
|
||||
%span.sr-only Déplacer le champ vers le bas
|
||||
.cell.flex.justify-start.column.flex-grow
|
||||
= form.label :type_champ, "Type de champ", for: dom_id(type_de_champ, :type_champ)
|
||||
= form.select :type_champ, grouped_options_for_select(types_of_type_de_champ, type_de_champ.type_champ), {}, class: 'small-margin small inline width-100', id: dom_id(type_de_champ, :type_champ), disabled: coordinate.used_by_routing_rules?
|
||||
.flex.column.justify-start.flex-grow
|
||||
.cell
|
||||
.flex.align-center
|
||||
= form.label :libelle, "Libellé du champ", class: 'flex-grow', for: dom_id(type_de_champ, :libelle)
|
||||
- if can_be_mandatory?
|
||||
.cell.flex.align-center
|
||||
= form.check_box :mandatory, class: 'small-margin small', id: dom_id(type_de_champ, :mandatory)
|
||||
= form.label :mandatory, "Champ obligatoire", for: dom_id(type_de_champ, :mandatory)
|
||||
= form.text_field :libelle, class: 'small-margin small width-100', id: dom_id(type_de_champ, :libelle), data: input_autofocus
|
||||
- if type_de_champ.header_section?
|
||||
%p
|
||||
%small Nous numérotons automatiquement les titres lorsqu’aucun de vos titres ne commence par un chiffre.
|
||||
.flex.justify-start.section.ml-1
|
||||
= form_for(type_de_champ, form_options) do |form|
|
||||
.flex.justify-start
|
||||
.flex.justify-start.width-33
|
||||
.flex.justify-start.column
|
||||
%button.move-up.cell.mb-1{ move_button_options(:up) }
|
||||
.icon.arrow-up.small
|
||||
%span.sr-only Déplacer le champ vers le haut
|
||||
%button.move-down.cell{ move_button_options(:down) }
|
||||
.icon.arrow-down.small
|
||||
%span.sr-only Déplacer le champ vers le bas
|
||||
.cell.flex.justify-start.column.flex-grow
|
||||
= form.label :type_champ, "Type de champ", for: dom_id(type_de_champ, :type_champ)
|
||||
= form.select :type_champ, grouped_options_for_select(types_of_type_de_champ, type_de_champ.type_champ), {}, class: 'fr-select small-margin small inline width-100', id: dom_id(type_de_champ, :type_champ), disabled: coordinate.used_by_routing_rules?
|
||||
|
||||
- if !type_de_champ.header_section? && !type_de_champ.titre_identite?
|
||||
.cell.mt-1
|
||||
= form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description)
|
||||
= form.text_area :description, class: 'small-margin small width-100', rows: 3, id: dom_id(type_de_champ, :description)
|
||||
- if type_de_champ.header_section?
|
||||
.cell.mt-1
|
||||
= render TypesDeChampEditor::HeaderSectionComponent.new(form: form, tdc: type_de_champ, upper_tdcs: @upper_coordinates.map(&:type_de_champ))
|
||||
|
||||
|
||||
|
||||
.flex.justify-start.mt-1
|
||||
- if type_de_champ.drop_down_list?
|
||||
.flex.column.justify-start.width-33
|
||||
.cell
|
||||
= form.label :drop_down_list_value, "Options de la liste", for: dom_id(type_de_champ, :drop_down_list_value)
|
||||
= form.text_area :drop_down_list_value, class: 'small-margin small width-100', rows: 7, id: dom_id(type_de_champ, :drop_down_list_value)
|
||||
- if type_de_champ.simple_drop_down_list?
|
||||
.cell
|
||||
= form.label :drop_down_other, for: dom_id(type_de_champ, :drop_down_other) do
|
||||
Proposer une option « autre » avec un texte libre
|
||||
= form.check_box :drop_down_other, class: "small-margin small", id: dom_id(type_de_champ, :drop_down_other)
|
||||
|
||||
- if type_de_champ.linked_drop_down_list?
|
||||
.flex.column.justify-start.flex-grow
|
||||
.cell
|
||||
= form.label :drop_down_secondary_libelle, "Libellé du champ secondaire", class: 'flex-grow', for: dom_id(type_de_champ, :drop_down_secondary_libelle)
|
||||
= form.text_field :drop_down_secondary_libelle, class: 'small-margin small width-100', id: dom_id(type_de_champ, :drop_down_secondary_libelle)
|
||||
.cell.mt-1
|
||||
= form.label :drop_down_secondary_description, "Description du champ secondaire (optionnel)", for: dom_id(type_de_champ, :drop_down_secondary_description)
|
||||
= form.text_area :drop_down_secondary_description, class: 'small-margin small width-100', rows: 3, id: dom_id(type_de_champ, :drop_down_secondary_description)
|
||||
- if type_de_champ.piece_justificative?
|
||||
.cell
|
||||
= form.label :piece_justificative_template, "Modèle", for: dom_id(type_de_champ, :piece_justificative_template)
|
||||
= render Attachment::EditComponent.new(**piece_justificative_template_options)
|
||||
.flex.align-center
|
||||
= form.label :libelle, "Libellé du champ", class: 'flex-grow', for: dom_id(type_de_champ, :libelle)
|
||||
- if can_be_mandatory?
|
||||
.cell.flex.align-center
|
||||
= form.check_box :mandatory, class: 'small-margin small', id: dom_id(type_de_champ, :mandatory)
|
||||
= form.label :mandatory, "Champ obligatoire", for: dom_id(type_de_champ, :mandatory)
|
||||
= form.text_field :libelle, class: 'fr-input small-margin small width-100', id: dom_id(type_de_champ, :libelle), data: input_autofocus
|
||||
- if type_de_champ.header_section?
|
||||
%p
|
||||
%small Nous numérotons automatiquement les titres lorsqu’aucun de vos titres ne commence par un chiffre.
|
||||
|
||||
- if type_de_champ.titre_identite?
|
||||
%p Dans le cadre de la RGPD, le titre d’identité sera supprimé lors de l’acceptation du dossier
|
||||
- elsif procedure.piece_justificative_multiple?
|
||||
%p Les usagers pourront envoyer plusieurs fichiers si nécessaire.
|
||||
- if type_de_champ.carte?
|
||||
- type_de_champ.editable_options.each do |slice|
|
||||
- if !type_de_champ.header_section? && !type_de_champ.titre_identite?
|
||||
.cell.mt-1
|
||||
= form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description)
|
||||
= form.text_area :description, class: 'fr-input small-margin small width-100', rows: 3, id: dom_id(type_de_champ, :description)
|
||||
- if type_de_champ.header_section?
|
||||
.cell.mt-1
|
||||
= render TypesDeChampEditor::HeaderSectionComponent.new(form: form, tdc: type_de_champ, upper_tdcs: @upper_coordinates.map(&:type_de_champ))
|
||||
|
||||
|
||||
|
||||
.flex.justify-start.mt-1
|
||||
- if type_de_champ.drop_down_list?
|
||||
.flex.column.justify-start.width-33
|
||||
.cell
|
||||
= form.label :drop_down_list_value, "Options de la liste", for: dom_id(type_de_champ, :drop_down_list_value)
|
||||
= form.text_area :drop_down_list_value, class: 'fr-input small-margin small width-100', rows: 7, id: dom_id(type_de_champ, :drop_down_list_value)
|
||||
- if type_de_champ.simple_drop_down_list?
|
||||
.cell
|
||||
= form.label :drop_down_other, for: dom_id(type_de_champ, :drop_down_other) do
|
||||
Proposer une option « autre » avec un texte libre
|
||||
= form.check_box :drop_down_other, class: "small-margin small", id: dom_id(type_de_champ, :drop_down_other)
|
||||
|
||||
- if type_de_champ.linked_drop_down_list?
|
||||
.flex.column.justify-start.flex-grow
|
||||
.cell
|
||||
= form.label :drop_down_secondary_libelle, "Libellé du champ secondaire", class: 'flex-grow', for: dom_id(type_de_champ, :drop_down_secondary_libelle)
|
||||
= form.text_field :drop_down_secondary_libelle, class: 'fr-input small-margin small width-100', id: dom_id(type_de_champ, :drop_down_secondary_libelle)
|
||||
.cell.mt-1
|
||||
= form.label :drop_down_secondary_description, "Description du champ secondaire (optionnel)", for: dom_id(type_de_champ, :drop_down_secondary_description)
|
||||
= form.text_area :drop_down_secondary_description, class: 'fr-input small-margin small width-100', rows: 3, id: dom_id(type_de_champ, :drop_down_secondary_description)
|
||||
- if type_de_champ.piece_justificative?
|
||||
.cell
|
||||
.carte-options
|
||||
= form.fields_for :editable_options do |form|
|
||||
- slice.each do |(name, checked)|
|
||||
= form.label name, for: dom_id(type_de_champ, "layer_#{name}") do
|
||||
= form.check_box name, checked: checked, class: 'small-margin small', id: dom_id(type_de_champ, "layer_#{name}")
|
||||
= t(".layers.#{name}")
|
||||
- if type_de_champ.explication?
|
||||
.cell.width-66
|
||||
= form.label :collapsible_explanation_enabled, for: dom_id(type_de_champ, :collapsible_explanation_enabled) do
|
||||
Afficher un texte complementaire affichable au clic
|
||||
= form.check_box :collapsible_explanation_enabled, class: "small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_enabled)
|
||||
- if form.object.collapsible_explanation_enabled?
|
||||
= form.label :collapsible_explanation_text, for: dom_id(type_de_champ, :collapsible_explanation_text) do
|
||||
= "Texte à afficher quand l'utiliser a choisi de l'afficher"
|
||||
= form.text_area :collapsible_explanation_text, class: "small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_text)
|
||||
- if type_de_champ.textarea?
|
||||
.cell
|
||||
= form.label :character_limit, for: dom_id(type_de_champ, :character_limit) do
|
||||
Spécifier un nombre maximal conseillé de caractères :
|
||||
= form.select :character_limit, options_for_character_limit, id: dom_id(type_de_champ, :character_limit)
|
||||
= form.label :piece_justificative_template, "Modèle", for: dom_id(type_de_champ, :piece_justificative_template)
|
||||
= render Attachment::EditComponent.new(**piece_justificative_template_options)
|
||||
|
||||
- if type_de_champ.block?
|
||||
.flex.justify-start.section.ml-1
|
||||
.editor-block.flex-grow.cell
|
||||
= render TypesDeChampEditor::BlockComponent.new(block: coordinate, coordinates: coordinate.revision_types_de_champ, upper_coordinates: @upper_coordinates)
|
||||
= render TypesDeChampEditor::AddChampButtonComponent.new(revision: coordinate.revision, parent: coordinate, is_annotation: coordinate.private?)
|
||||
- if type_de_champ.titre_identite?
|
||||
%p Dans le cadre de la RGPD, le titre d’identité sera supprimé lors de l’acceptation du dossier
|
||||
- elsif procedure.piece_justificative_multiple?
|
||||
%p Les usagers pourront envoyer plusieurs fichiers si nécessaire.
|
||||
- if type_de_champ.carte?
|
||||
- type_de_champ.editable_options.each do |slice|
|
||||
.cell
|
||||
.carte-options
|
||||
= form.fields_for :editable_options do |form|
|
||||
- slice.each do |(name, checked)|
|
||||
= form.label name, for: dom_id(type_de_champ, "layer_#{name}") do
|
||||
= form.check_box name, checked: checked, class: 'small-margin small', id: dom_id(type_de_champ, "layer_#{name}")
|
||||
= t(".layers.#{name}")
|
||||
- if type_de_champ.explication?
|
||||
.cell.width-66
|
||||
= form.label :collapsible_explanation_enabled, for: dom_id(type_de_champ, :collapsible_explanation_enabled) do
|
||||
Afficher un texte complementaire affichable au clic
|
||||
= form.check_box :collapsible_explanation_enabled, class: "small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_enabled)
|
||||
- if form.object.collapsible_explanation_enabled?
|
||||
= form.label :collapsible_explanation_text, for: dom_id(type_de_champ, :collapsible_explanation_text) do
|
||||
= "Texte à afficher quand l'utiliser a choisi de l'afficher"
|
||||
= form.text_area :collapsible_explanation_text, class: "fr-input small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_text)
|
||||
- if type_de_champ.textarea?
|
||||
.cell
|
||||
= form.label :character_limit, for: dom_id(type_de_champ, :character_limit) do
|
||||
Spécifier un nombre maximal conseillé de caractères :
|
||||
= form.select :character_limit, options_for_character_limit, id: dom_id(type_de_champ, :character_limit), class: 'fr-select'
|
||||
|
||||
- if conditional_enabled?
|
||||
= render(TypesDeChampEditor::ConditionsComponent.new(tdc: type_de_champ, upper_tdcs: @upper_coordinates.map(&:type_de_champ), procedure_id: procedure.id))
|
||||
- if type_de_champ.block?
|
||||
.flex.justify-start.section.ml-1
|
||||
.editor-block.flex-grow.cell
|
||||
= render TypesDeChampEditor::BlockComponent.new(block: coordinate, coordinates: coordinate.revision_types_de_champ, upper_coordinates: @upper_coordinates)
|
||||
.type-de-champ-add-button{ id: dom_id(coordinate, :type_de_champ_add_button), class: class_names(hidden: !coordinate.empty?) }
|
||||
= render TypesDeChampEditor::AddChampButtonComponent.new(revision: coordinate.revision, parent: coordinate, is_annotation: coordinate.private?)
|
||||
|
||||
- if conditional_enabled?
|
||||
= render(TypesDeChampEditor::ConditionsComponent.new(tdc: type_de_champ, upper_tdcs: @upper_coordinates.map(&:type_de_champ), procedure_id: procedure.id))
|
||||
|
||||
.type-de-champ-add-button{ class: class_names(root: !coordinate.child?) }
|
||||
= render TypesDeChampEditor::AddChampButtonComponent.new(revision: coordinate.revision, parent: coordinate&.parent, is_annotation: coordinate.private?, after_stable_id: type_de_champ.stable_id)
|
||||
|
|
|
@ -9,7 +9,13 @@ module Administrateurs
|
|||
|
||||
right = targeted_champ_changed? ? empty : value
|
||||
|
||||
groupe_instructeur.update!(routing_rule: ds_eq(left, right))
|
||||
new_routing_rule = case operator_name
|
||||
when Eq.name
|
||||
ds_eq(left, right)
|
||||
when NotEq.name
|
||||
ds_not_eq(left, right)
|
||||
end
|
||||
groupe_instructeur.update!(routing_rule: new_routing_rule)
|
||||
end
|
||||
|
||||
def update_defaut_groupe_instructeur
|
||||
|
@ -27,6 +33,10 @@ module Administrateurs
|
|||
Logic.from_json(params[:targeted_champ])
|
||||
end
|
||||
|
||||
def operator_name
|
||||
params[:operator_name]
|
||||
end
|
||||
|
||||
def value
|
||||
Logic.from_json(params[:value])
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class API::Public::V1::DossiersController < API::Public::V1::BaseController
|
|||
)
|
||||
dossier.build_default_individual
|
||||
if dossier.save
|
||||
dossier.prefill!(PrefillParams.new(dossier, params.to_unsafe_h).to_a)
|
||||
dossier.prefill!(PrefillChamps.new(dossier, params.to_unsafe_h).to_a, PrefillIdentity.new(dossier, params.to_unsafe_h).to_h)
|
||||
render json: serialize_dossier(dossier), status: :created
|
||||
else
|
||||
render_bad_request(dossier.errors.full_messages.to_sentence)
|
||||
|
|
|
@ -25,6 +25,7 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
before_action do
|
||||
Current.request_id = request.uuid
|
||||
Current.user = current_user
|
||||
end
|
||||
|
||||
def staging_authenticate
|
||||
|
|
|
@ -25,6 +25,6 @@ class PrefillDescriptionsController < ApplicationController
|
|||
end
|
||||
|
||||
def prefill_description_params
|
||||
params.require(:type_de_champ).permit(:selected_type_de_champ_ids)
|
||||
params.require(:procedure).permit(:selected_type_de_champ_ids, :identity_items_selected)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -78,11 +78,11 @@ module Users
|
|||
end
|
||||
|
||||
def commencer_page_is_reloaded?
|
||||
session[:prefill_token].present? && session[:prefill_params_digest] == PrefillParams.digest(params)
|
||||
session[:prefill_token].present? && session[:prefill_params_digest] == PrefillChamps.digest(params)
|
||||
end
|
||||
|
||||
def prefill_params_present?
|
||||
params.keys.find { |param| param.split('_').first == "champ" }
|
||||
params.keys.find { ['champ', 'identite'].include?(_1.split('_').first) }
|
||||
end
|
||||
|
||||
def retrieve_procedure
|
||||
|
@ -101,10 +101,10 @@ module Users
|
|||
)
|
||||
@prefilled_dossier.build_default_individual
|
||||
if @prefilled_dossier.save
|
||||
@prefilled_dossier.prefill!(PrefillParams.new(@prefilled_dossier, params.to_unsafe_h).to_a)
|
||||
@prefilled_dossier.prefill!(PrefillChamps.new(@prefilled_dossier, params.to_unsafe_h).to_a, PrefillIdentity.new(@prefilled_dossier, params.to_unsafe_h).to_h)
|
||||
end
|
||||
session[:prefill_token] = @prefilled_dossier.prefill_token
|
||||
session[:prefill_params_digest] = PrefillParams.digest(params)
|
||||
session[:prefill_params_digest] = PrefillChamps.digest(params)
|
||||
end
|
||||
|
||||
def retrieve_prefilled_dossier(prefill_token)
|
||||
|
|
|
@ -14,6 +14,8 @@ class ProcedureDashboard < Administrate::BaseDashboard
|
|||
aasm_state: ProcedureStateField,
|
||||
dossiers: Field::HasMany,
|
||||
administrateurs: Field::HasMany,
|
||||
instructeurs: Field::HasMany,
|
||||
groupe_instructeurs: Field::HasMany,
|
||||
id: Field::Number.with_options(searchable: true),
|
||||
libelle: Field::String,
|
||||
description: Field::String,
|
||||
|
@ -68,6 +70,8 @@ class ProcedureDashboard < Administrate::BaseDashboard
|
|||
:path,
|
||||
:aasm_state,
|
||||
:administrateurs,
|
||||
:instructeurs,
|
||||
:groupe_instructeurs,
|
||||
:libelle,
|
||||
:description,
|
||||
:tags,
|
||||
|
|
|
@ -13,7 +13,7 @@ import type { Style } from 'maplibre-gl';
|
|||
|
||||
import invariant from 'tiny-invariant';
|
||||
|
||||
import { useStyle } from './hooks';
|
||||
import { useStyle, useElementVisible } from './hooks';
|
||||
import { StyleControl } from './StyleControl';
|
||||
|
||||
const Context = createContext<{ map?: Map | null }>({});
|
||||
|
@ -35,6 +35,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
|||
[]
|
||||
);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const visible = useElementVisible(containerRef);
|
||||
const [map, setMap] = useState<Map | null>();
|
||||
|
||||
const onStyleChange = useCallback(
|
||||
|
@ -48,7 +49,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
|||
const { style, ...mapStyleProps } = useStyle(layers, onStyleChange);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSupported && !map) {
|
||||
if (isSupported && visible && !map) {
|
||||
invariant(containerRef.current, 'Map container not found');
|
||||
const map = new Map({
|
||||
container: containerRef.current,
|
||||
|
@ -59,7 +60,7 @@ export function MapLibre({ children, layers }: MapLibreProps) {
|
|||
setMap(map);
|
||||
});
|
||||
}
|
||||
}, [map, style, isSupported]);
|
||||
}, [map, style, visible, isSupported]);
|
||||
|
||||
if (!isSupported) {
|
||||
return (
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
useMemo,
|
||||
type RefObject
|
||||
} from 'react';
|
||||
import type {
|
||||
LngLatBoundsLike,
|
||||
LngLat,
|
||||
|
@ -118,3 +124,30 @@ export function useStyle(
|
|||
|
||||
return { style, layers, setStyle, setLayerEnabled, setLayerOpacity };
|
||||
}
|
||||
|
||||
function isElementVisible(
|
||||
element: HTMLElement,
|
||||
callback: (visible: boolean) => void
|
||||
) {
|
||||
if (element.offsetWidth > 0 && element.offsetHeight > 0) {
|
||||
callback(true);
|
||||
} else {
|
||||
callback(false);
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => callback(entries[0].isIntersecting == true),
|
||||
{ threshold: [0] }
|
||||
);
|
||||
observer.observe(element);
|
||||
return () => observer.unobserve(element);
|
||||
}
|
||||
}
|
||||
|
||||
export function useElementVisible(element: RefObject<HTMLElement>) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
useEffect(() => {
|
||||
if (element.current) {
|
||||
return isElementVisible(element.current, setVisible);
|
||||
}
|
||||
}, [element]);
|
||||
return visible;
|
||||
}
|
||||
|
|
|
@ -124,12 +124,12 @@ export class AutosaveController extends ApplicationController {
|
|||
private showSpinner(champElement: Element) {
|
||||
this.#spinnerTimeoutId = setTimeout(() => {
|
||||
// do not do anything if there is already a spinner for this champ, like SIRET champ
|
||||
if (!champElement.querySelector('.spinner')) {
|
||||
if (!champElement.nextElementSibling?.classList.contains('spinner')) {
|
||||
const spinner = document.createElement('div');
|
||||
spinner.classList.add('spinner', 'spinner-removable');
|
||||
spinner.setAttribute('aria-live', 'live');
|
||||
spinner.setAttribute('aria-label', 'Chargement en cours…');
|
||||
champElement.appendChild(spinner);
|
||||
champElement.insertAdjacentElement('afterend', spinner);
|
||||
}
|
||||
}, AUTOSAVE_CONDITIONAL_SPINNER_DEBOUNCE_DELAY);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
isTextInputElement,
|
||||
getConfig
|
||||
} from '@utils';
|
||||
import { useIntersection } from 'stimulus-use';
|
||||
import { AutoUpload } from '../shared/activestorage/auto-upload';
|
||||
import { ApplicationController } from './application_controller';
|
||||
|
||||
|
@ -28,7 +27,6 @@ export class TypeDeChampEditorController extends ApplicationController {
|
|||
declare readonly moveUrlValue: string;
|
||||
declare readonly moveUpUrlValue: string;
|
||||
declare readonly moveDownUrlValue: string;
|
||||
declare readonly typeDeChampStableIdValue: string;
|
||||
declare readonly isVisible: boolean;
|
||||
|
||||
#latestPromise = Promise.resolve();
|
||||
|
@ -36,8 +34,6 @@ export class TypeDeChampEditorController extends ApplicationController {
|
|||
#inFlightForms: Map<HTMLFormElement, AbortController> = new Map();
|
||||
|
||||
connect() {
|
||||
useIntersection(this, { threshold: 0.6 });
|
||||
|
||||
this.#latestPromise = Promise.resolve();
|
||||
this.on('change', (event) => this.onChange(event));
|
||||
this.on('input', (event) => this.onInput(event));
|
||||
|
@ -62,10 +58,6 @@ export class TypeDeChampEditorController extends ApplicationController {
|
|||
this.requestSubmitForm(form);
|
||||
}
|
||||
|
||||
appear() {
|
||||
this.updateAfterId();
|
||||
}
|
||||
|
||||
private onChange(event: Event) {
|
||||
const target = event.target as HTMLElement & { form?: HTMLFormElement };
|
||||
|
||||
|
@ -144,28 +136,8 @@ export class TypeDeChampEditorController extends ApplicationController {
|
|||
this.#inFlightForms.set(form, controller);
|
||||
return controller;
|
||||
}
|
||||
|
||||
private updateAfterId() {
|
||||
const parent = this.element.closest<HTMLElement>(
|
||||
'.editor-block, .editor-root'
|
||||
);
|
||||
if (parent) {
|
||||
const selector = parent.classList.contains('editor-block')
|
||||
? '.add-to-block'
|
||||
: '.add-to-root';
|
||||
const input = parent.querySelector<HTMLInputElement>(
|
||||
`${selector} ${AFTER_STABLE_ID_INPUT_SELECTOR}`
|
||||
);
|
||||
if (input) {
|
||||
input.value = this.typeDeChampStableIdValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const AFTER_STABLE_ID_INPUT_SELECTOR =
|
||||
'input[name="type_de_champ[after_stable_id]"]';
|
||||
|
||||
function createForm(action: string, method: string) {
|
||||
const form = document.createElement('form');
|
||||
form.action = action;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createGraphiQLFetcher } from '@graphiql/toolkit';
|
||||
import { useExplorerPlugin } from '@graphiql/plugin-explorer';
|
||||
import { explorerPlugin } from '@graphiql/plugin-explorer';
|
||||
import { GraphiQL } from 'graphiql';
|
||||
import { createElement, useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
@ -17,15 +17,11 @@ const fetcher = createGraphiQLFetcher({
|
|||
|
||||
function GraphiQLWithExplorer() {
|
||||
const [query, setQuery] = useState(defaultQuery);
|
||||
const explorerPlugin = useExplorerPlugin({
|
||||
query: query ?? '',
|
||||
onEdit: setQuery,
|
||||
showAttribution: false
|
||||
});
|
||||
const explorer = explorerPlugin({ showAttribution: false });
|
||||
return createElement(GraphiQL, {
|
||||
fetcher: fetcher,
|
||||
defaultEditorToolsVisibility: true,
|
||||
plugins: [explorerPlugin],
|
||||
plugins: [explorer],
|
||||
query: query,
|
||||
variables: defaultVariables,
|
||||
onEditQuery: setQuery,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require 'fog/openstack'
|
||||
|
||||
class PjsMigrationJob < ApplicationJob
|
||||
queue_as :pj_migration_jobs
|
||||
|
||||
|
@ -7,7 +9,6 @@ class PjsMigrationJob < ApplicationJob
|
|||
return if already_moved?(blob)
|
||||
|
||||
service = blob.service
|
||||
client = service.client
|
||||
container = service.container
|
||||
old_key = blob.key
|
||||
new_key = "#{blob.created_at.strftime('%Y/%m/%d')}/#{old_key[0..1]}/#{old_key}"
|
||||
|
@ -28,4 +29,14 @@ class PjsMigrationJob < ApplicationJob
|
|||
def already_moved?(blob)
|
||||
blob.key.include?('/')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def client
|
||||
@client ||= begin
|
||||
credentials = Rails.application.config.active_storage
|
||||
.service_configurations['openstack']['credentials']
|
||||
Fog::OpenStack::Storage.new(credentials)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require 'fog/openstack'
|
||||
|
||||
class ActiveStorage::DownloadableFile
|
||||
def self.create_list_from_dossiers(
|
||||
dossiers,
|
||||
|
@ -20,7 +22,6 @@ class ActiveStorage::DownloadableFile
|
|||
true
|
||||
else
|
||||
service = file.blob.service
|
||||
client = service.client
|
||||
begin
|
||||
client.head_object(service.container, file.blob.key)
|
||||
true
|
||||
|
@ -33,6 +34,13 @@ class ActiveStorage::DownloadableFile
|
|||
|
||||
private
|
||||
|
||||
def self.client
|
||||
credentials = Rails.application.config.active_storage
|
||||
.service_configurations['openstack']['credentials']
|
||||
|
||||
Fog::OpenStack::Storage.new(credentials)
|
||||
end
|
||||
|
||||
def self.bill_and_path(bill)
|
||||
[
|
||||
bill,
|
||||
|
|
|
@ -160,6 +160,14 @@ class Champ < ApplicationRecord
|
|||
true
|
||||
end
|
||||
|
||||
def legend_label?
|
||||
false
|
||||
end
|
||||
|
||||
def single_checkbox?
|
||||
false
|
||||
end
|
||||
|
||||
def input_group_id
|
||||
"champ-#{html_id}"
|
||||
end
|
||||
|
|
|
@ -7,11 +7,23 @@ class Champs::CheckboxChamp < Champs::BooleanChamp
|
|||
mandatory? && (blank? || !true?)
|
||||
end
|
||||
|
||||
def legend_label?
|
||||
false
|
||||
end
|
||||
|
||||
# TODO remove when normalize_checkbox_values is over
|
||||
def true?
|
||||
value_with_legacy == TRUE_VALUE
|
||||
end
|
||||
|
||||
def html_label?
|
||||
false
|
||||
end
|
||||
|
||||
def single_checkbox?
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# TODO remove when normalize_checkbox_values is over
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue