Merge branch 'main' into feature-ouidou/existing_procedure_hidden_as_template
|
@ -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' }
|
||||
|
|
7
.github/actions/ci-setup-rails/action.yml
vendored
|
@ -12,7 +12,12 @@ runs:
|
|||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install yarn
|
||||
run: |
|
||||
npm install --global yarn
|
||||
shell: bash
|
||||
|
||||
- name: Install Node modules
|
||||
run: |
|
||||
|
|
5
.github/workflows/ci.yml
vendored
|
@ -75,6 +75,9 @@ jobs:
|
|||
- name: Setup the app runtime and dependencies
|
||||
uses: ./.github/actions/ci-setup-rails
|
||||
|
||||
- name: Install fonts pickable by ImageMagick
|
||||
run: sudo apt-get install -y gsfonts
|
||||
|
||||
- name: Pre-compile assets
|
||||
uses: ./.github/actions/ci-setup-assets
|
||||
|
||||
|
@ -97,7 +100,7 @@ jobs:
|
|||
|
||||
system_tests:
|
||||
name: System tests
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: self-hosted
|
||||
services:
|
||||
postgres:
|
||||
image: postgis/postgis:14-3.3
|
||||
|
|
|
@ -1 +1 @@
|
|||
16.14.0
|
||||
18.17.0
|
||||
|
|
|
@ -41,11 +41,11 @@ demarches-simplifiees.fr est **compliqué à héberger**. Parmi les problématiq
|
|||
- **Utilisation de services externes** : demarches-simplifiees.fr s’interconnecte à de nombreux services externes : des APIs (API Entreprise, API Carto, la Base Adresse Nationale, etc.) – mais aussi des services pour le stockage externe des pièces-jointes, l’analyse anti-virus ou l’envoi des emails. Le fonctionnement de demarches-simplifiees.fr dépend de la disponibilité de ces services externes.
|
||||
- **Mises à jour** : le schéma de la base de données change régulièrement. Nous codons également des scripts pour harmoniser les anciennes données. Parfois des modifications ponctuelles sont effectuées sur des démarches anciennes, pour les mettre en conformité avec de nouvelles règles métiers. Nous maintenons également les dépendances logicielles utilisées – notamment en réagissant rapidement lorsqu’une faille de sécurité est signalée. Ces mises à jour fréquentes en production sont indispensables au bon fonctionnement de l’outil.
|
||||
|
||||
Si vous souhaitez adapter demarches-simplifiees.fr à votre besoin, nous vous recommandons de **proposer vos modifications à la base de code principale** (par exemple en créant une issue) **plutôt que d’héberger une autre instance vous-même**.
|
||||
Si vous souhaitez adapter demarches-simplifiees.fr à vos besoins, nous vous recommandons de **proposer vos modifications à la base de code principale** (par exemple en créant une issue) **plutôt que d’héberger une autre instance vous-même**.
|
||||
|
||||
Dans le cas où vous envisagez d’héberger une instance de demarches-simplifiees.fr vous-même, nous n'avons malheureusement pas les moyens de vous accompagner, ni d’assurer de support technique concernant votre installation.
|
||||
Dans le cas où vous envisagez d’héberger une instance de demarches-simplifiees.fr vous-même, nous ne disposons malheureusement pas des moyens pour vous accompagner, ni d’assurer de support technique concernant votre installation.
|
||||
|
||||
Toutefois, certains acteurs (le ministère des armées, l’administration autonome en Polynésie française) ont déployé des instances séparées. Nous proposons aux personnes intéressées de les mettre en relation avec ces acteurs existants, afin de disposer d’un retour d’expérience, et de bénéficier de leur retour.
|
||||
Toutefois, certains acteurs (le ministère des armées, l’administration autonome en Polynésie française, l'association Adullact) ont déployé des instances séparées. Nous proposons aux personnes intéressées de les mettre en relation avec ces acteurs existants, pour obtenir un retour d’expérience et bénéficier de leur retour.
|
||||
|
||||
## Bonnes pratiques de code
|
||||
|
||||
|
|
3
Gemfile
|
@ -59,6 +59,7 @@ gem 'lograge'
|
|||
gem 'logstash-event'
|
||||
gem 'mailjet', require: false
|
||||
gem 'matrix' # needed by prawn and not default in ruby 3.1
|
||||
gem 'mini_magick'
|
||||
gem 'net-imap', require: false # See https://github.com/mikel/mail/pull/1439
|
||||
gem 'net-pop', require: false # same
|
||||
gem 'net-smtp', require: false # same
|
||||
|
@ -105,6 +106,7 @@ group :test do
|
|||
gem 'rack_session_access'
|
||||
gem 'rails-controller-testing'
|
||||
gem 'rspec_junit_formatter'
|
||||
gem 'rspec-retry'
|
||||
gem 'selenium-devtools'
|
||||
gem 'selenium-webdriver'
|
||||
gem 'shoulda-matchers', require: false
|
||||
|
@ -114,7 +116,6 @@ group :test do
|
|||
end
|
||||
|
||||
group :development do
|
||||
gem 'annotate'
|
||||
gem 'brakeman', require: false
|
||||
gem 'haml-lint'
|
||||
gem 'letter_opener_web'
|
||||
|
|
165
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)
|
||||
|
@ -101,9 +101,6 @@ GEM
|
|||
aes_key_wrap (1.1.0)
|
||||
after_party (1.11.2)
|
||||
anchored (1.1.0)
|
||||
annotate (3.2.0)
|
||||
activerecord (>= 3.2, < 8.0)
|
||||
rake (>= 10.4, < 14.0)
|
||||
ast (2.4.2)
|
||||
attr_required (1.0.1)
|
||||
axe-core-api (4.2.1)
|
||||
|
@ -239,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)
|
||||
|
@ -257,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)
|
||||
|
@ -352,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)
|
||||
|
@ -389,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)
|
||||
|
@ -417,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)
|
||||
|
@ -442,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)
|
||||
|
@ -490,13 +485,13 @@ GEM
|
|||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (5.0.1)
|
||||
puma (6.1.1)
|
||||
puma (6.3.1)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.2.0)
|
||||
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)
|
||||
|
@ -516,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)
|
||||
|
@ -548,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)
|
||||
|
@ -558,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)
|
||||
|
@ -604,6 +600,8 @@ GEM
|
|||
rspec-expectations (~> 3.11)
|
||||
rspec-mocks (~> 3.11)
|
||||
rspec-support (~> 3.11)
|
||||
rspec-retry (0.6.2)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.12.0)
|
||||
rspec_junit_formatter (0.4.1)
|
||||
rspec-core (>= 2, < 4, != 2.12.0)
|
||||
|
@ -690,7 +688,7 @@ GEM
|
|||
rack (~> 2.2, >= 2.2.4)
|
||||
rack-protection (= 3.0.5)
|
||||
tilt (~> 2.0)
|
||||
skylight (5.3.4)
|
||||
skylight (6.0.1)
|
||||
activesupport (>= 5.2.0)
|
||||
smart_properties (1.17.0)
|
||||
spreadsheet_architect (4.1.0)
|
||||
|
@ -778,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)
|
||||
|
@ -790,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)
|
||||
|
@ -813,7 +811,6 @@ DEPENDENCIES
|
|||
administrate-field-enum
|
||||
after_party
|
||||
anchored
|
||||
annotate
|
||||
axe-core-rspec
|
||||
bcrypt
|
||||
bootsnap (>= 1.4.4)
|
||||
|
@ -872,6 +869,7 @@ DEPENDENCIES
|
|||
matrix
|
||||
memory_profiler
|
||||
mina
|
||||
mini_magick
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
|
@ -898,6 +896,7 @@ DEPENDENCIES
|
|||
rexml
|
||||
rqrcode
|
||||
rspec-rails
|
||||
rspec-retry
|
||||
rspec_junit_formatter
|
||||
rubocop
|
||||
rubocop-performance
|
||||
|
|
|
@ -17,6 +17,7 @@ Vous souhaitez y apporter des changements ou des améliorations ? Lisez notre [
|
|||
#### Tous environnements
|
||||
|
||||
- postgresql
|
||||
- imagemagick et gsfonts pour générer les filigranes sur les titres d'identité.
|
||||
|
||||
#### Développement
|
||||
|
||||
|
@ -28,7 +29,7 @@ Vous souhaitez y apporter des changements ou des améliorations ? Lisez notre [
|
|||
- Chrome
|
||||
- chromedriver :
|
||||
* Mac : `brew install chromedriver`
|
||||
* Linux : voir https://sites.google.com/a/chromium.org/chromedriver/downloads
|
||||
* Linux : voir https://developer.chrome.com/blog/chrome-for-testing
|
||||
|
||||
Si l'emplacement d'installation de Chrome n'est pas standard, ou que vous utilisez Brave ou Chromium à la place,
|
||||
il peut être nécessaire d'overrider pour votre machine le path vers le binaire Chrome, par exemple :
|
||||
|
@ -42,8 +43,7 @@ Selenium::WebDriver::Chrome.path = "/Applications/Brave Browser.app/Contents/Mac
|
|||
Webdrivers::Chromedriver.required_version = "103.0.5060.53"
|
||||
```
|
||||
|
||||
Il peut être également pertinent de désactiver la mise à jour automatique du webdriver
|
||||
en définissant une variable d'environnement `SKIP_UPDATE_WEBDRIVER` lors de l'exécution de `bin/update`.
|
||||
Il est également possible de faire une installation et mise à jour automatique lors de l'exécution de `bin/update` en définissant la variable d'environnement `UPDATE_WEBDRIVER`. Les binaires seront installés dans le repertoire `~/.local/bin/` qui doit être rajouté manuellement dans le path.
|
||||
|
||||
### Création des rôles de la base de données
|
||||
|
||||
|
|
Before Width: | Height: | Size: 466 B After Width: | Height: | Size: 480 B |
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 878 B |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
app/assets/images/favicons/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 9.7 KiB |
|
@ -102,6 +102,10 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.width-max-content {
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
// sizing
|
||||
.width-100 {
|
||||
width: 100%;
|
||||
|
|
|
@ -10,12 +10,6 @@
|
|||
//
|
||||
// The procedure description can still be read from the /commencer
|
||||
// pages.
|
||||
@media (max-width: $two-columns-breakpoint) {
|
||||
.agent-intro {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
padding-top: $default-spacer;
|
||||
}
|
||||
|
@ -37,14 +31,6 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
background-color: $grey;
|
||||
border: none;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.register {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
:not(.fr-downloads-group) > ul {
|
||||
:not(.fr-downloads-group):not(.fr-pagination) > ul {
|
||||
list-style-type: disc;
|
||||
list-style-position: inside;
|
||||
padding-left: $default-padding;
|
||||
|
|
|
@ -62,11 +62,6 @@
|
|||
width: 110px;
|
||||
}
|
||||
|
||||
.action-col {
|
||||
text-align: right;
|
||||
padding-left: $default-spacer;
|
||||
padding-right: $default-spacer;
|
||||
}
|
||||
|
||||
.follow-col {
|
||||
width: 450px;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -631,3 +621,18 @@ textarea::placeholder {
|
|||
background-color: $white;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.fr-menu__list {
|
||||
padding: $default-spacer;
|
||||
overflow-y: auto;
|
||||
max-height: 300px;
|
||||
|
||||
.fr-menu__item {
|
||||
list-style-type: none;
|
||||
margin-bottom: $default-spacer;
|
||||
|
||||
&[aria-selected] {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,6 @@
|
|||
@import "constants";
|
||||
|
||||
#invites-form {
|
||||
padding: $default-padding;
|
||||
text-align: left;
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
margin-top: $default-padding;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: bold;
|
||||
margin-bottom: $default-spacer;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: $default-spacer;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-position: inside;
|
||||
list-style-type: disc;
|
||||
margin-bottom: $default-padding;
|
||||
}
|
||||
|
||||
input[type=email] {
|
||||
margin-bottom: $default-spacer;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-left: $default-spacer;
|
||||
@media (min-width: 48em) {
|
||||
min-width: 400px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -80,8 +89,6 @@
|
|||
}
|
||||
|
||||
&.type-header-section {
|
||||
background-color: $blue-cumulus-950;
|
||||
|
||||
.head {
|
||||
background-color: $blue-cumulus-950;
|
||||
}
|
||||
|
@ -91,10 +98,6 @@
|
|||
&.section {
|
||||
padding: $default-spacer $default-spacer 0;
|
||||
margin-bottom: 8px;
|
||||
|
||||
input {
|
||||
background-color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
&.hr {
|
||||
|
|
|
@ -65,3 +65,8 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hacky css to display dropdown "customize table" for table with only 1 or 2 lines
|
||||
table.min-height-300 {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
= render partial: "shared/champs/carte/show", locals: { champ: champ }
|
||||
- when TypeDeChamp.type_champs.fetch(:dossier_link)
|
||||
= render partial: "shared/champs/dossier_link/show", locals: { champ: champ }
|
||||
- when TypeDeChamp.type_champs.fetch(:drop_down_list)
|
||||
= render partial: "shared/champs/drop_down_list/show", locals: { champ: champ }
|
||||
- when TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
|
||||
= render partial: "shared/champs/multiple_drop_down_list/show", locals: { champ: champ }
|
||||
- when TypeDeChamp.type_champs.fetch(:piece_justificative), TypeDeChamp.type_champs.fetch(:titre_identite)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -15,10 +15,6 @@ class Dossiers::NotifiedToggleComponent < ApplicationComponent
|
|||
sorted_by_notifications? && order_desc?
|
||||
end
|
||||
|
||||
def icon_class_name
|
||||
active? ? 'fr-fi-checkbox' : 'fr-fi-checkbox-blank'
|
||||
end
|
||||
|
||||
def order_desc?
|
||||
current_order == 'desc'
|
||||
end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
= form_tag update_sort_instructeur_procedure_path(procedure_id: @procedure.id, table: 'notifications', column: 'notifications', order: opposite_order), method: :get, data: { controller: 'autosubmit' } do
|
||||
.fr-toggle
|
||||
= check_box_tag :order, opposite_order, active?, class: 'fr-toggle__input'
|
||||
= label_tag :order, t('.show_notified_first'), class: 'fr-toggle__label fr-pl-1w'
|
||||
= submit_tag t('.show_notified_first'), data: {"checkbox-target": 'submit' }, class: 'visually-hidden'
|
||||
.fr-fieldset__element.fr-m-0
|
||||
.fr-checkbox-group.fr-checkbox-group--sm
|
||||
= check_box_tag :order, opposite_order, active?
|
||||
= label_tag :order, t('.show_notified_first'), class: 'fr-label'
|
||||
= submit_tag t('.show_notified_first'), data: {"checkbox-target": 'submit' }, class: 'visually-hidden'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
= form_with(url: dossiers_path, method: :get, data: { controller: 'autosubmit' } ) do |f|
|
||||
= f.hidden_field :q, value: params[:q], id: nil
|
||||
= f.label :procedure_id, t('.procedure.label'), class: 'sr-only'
|
||||
.fr-input-group
|
||||
= f.select :procedure_id, options_for_select(@procedures_for_select, params[:procedure_id]), { prompt: t('.procedures.prompt') }, class: 'fr-select'
|
||||
|
|
65
app/components/dsfr/combobox_component.rb
Normal file
|
@ -0,0 +1,65 @@
|
|||
class Dsfr::ComboboxComponent < ApplicationComponent
|
||||
def initialize(form: nil, options:, selected: nil, allows_custom_value: false, **html_options)
|
||||
@form, @options, @selected, @allows_custom_value, @html_options = form, options, selected, allows_custom_value, html_options
|
||||
end
|
||||
|
||||
attr_reader :form, :options, :selected, :allows_custom_value
|
||||
|
||||
private
|
||||
|
||||
def name
|
||||
@html_options[:name]
|
||||
end
|
||||
|
||||
def form_id
|
||||
@html_options[:form_id]
|
||||
end
|
||||
|
||||
def html_input_options
|
||||
{
|
||||
type: 'text',
|
||||
autocomplete: 'off',
|
||||
spellcheck: 'false',
|
||||
id: input_id,
|
||||
class: input_class,
|
||||
value: input_value,
|
||||
'aria-expanded': 'false',
|
||||
'aria-describedby': @html_options[:describedby]
|
||||
}.compact
|
||||
end
|
||||
|
||||
def input_id
|
||||
@html_options[:id]
|
||||
end
|
||||
|
||||
def input_class
|
||||
"#{@html_options[:class].presence || ''} fr-select"
|
||||
end
|
||||
|
||||
def input_value
|
||||
selected.present? ? options_with_values.find { _1.last == selected }&.first : nil
|
||||
end
|
||||
|
||||
def list_id
|
||||
input_id.present? ? "#{input_id}-list" : nil
|
||||
end
|
||||
|
||||
def options_with_values
|
||||
options.map { _1.is_a?(Array) ? _1 : [_1, _1] }
|
||||
end
|
||||
|
||||
def options_json
|
||||
options_with_values.map { |(label, value)| { label:, value: } }.to_json
|
||||
end
|
||||
|
||||
def hints_json
|
||||
{
|
||||
empty: t(".sr.results", count: 0),
|
||||
one: t(".sr.results", count: 1),
|
||||
many: t(".sr.results", count: 2),
|
||||
oneWithLabel: t(".sr.results_with_label", count: 1),
|
||||
manyWithLabel: t(".sr.results_with_label", count: 2),
|
||||
selected: t(".sr.selected", count: 2)
|
||||
}.to_json
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
en:
|
||||
sr:
|
||||
results:
|
||||
zero: No result
|
||||
one: 1 result
|
||||
other: "{count} results"
|
||||
results_with_label:
|
||||
one: "1 result. {label} is the top result – press Enter to activate"
|
||||
other: "{count} results. {label} is the top result – press Enter to activate"
|
||||
selected: "{label} selected"
|
|
@ -0,0 +1,10 @@
|
|||
fr:
|
||||
sr:
|
||||
results:
|
||||
zero: Aucun résultat
|
||||
one: 1 résultat
|
||||
other: "{count} résultats"
|
||||
results_with_label:
|
||||
one: "1 résultat. {label} est le premier résultat – appuyez sur Entrée pour sélectionner"
|
||||
other: "{count} résultats. {label} est le premier résultat – appuyez sur Entrée pour sélectionner"
|
||||
selected: "{label} sélectionné"
|
|
@ -0,0 +1,13 @@
|
|||
.fr-ds-combobox{ data: { controller: 'combobox', allows_custom_value: allows_custom_value } }
|
||||
.fr-ds-combobox-input
|
||||
%input{ **html_input_options }
|
||||
- if form
|
||||
= form.hidden_field name, value: selected, form: form_id
|
||||
- else
|
||||
%input{ type: 'hidden', name:, value: selected, form: form_id }
|
||||
.fr-menu
|
||||
%ul.fr-menu__list.hidden{ role: 'listbox', hidden: true, id: list_id, data: { turbo_force: :browser, options: options_json, selected:, hints: hints_json } }
|
||||
.sr-only{ aria: { live: 'polite', atomic: 'true' }, data: { turbo_force: :browser } }
|
||||
%template
|
||||
%li.fr-menu__item{ role: 'option' }
|
||||
%slot{ name: 'label' }
|
|
@ -7,6 +7,7 @@ class Dsfr::InputComponent < ApplicationComponent
|
|||
# use it to indicate detailed about the inputs, ex: https://www.systeme-de-design.gouv.fr/elements-d-interface/modeles-et-blocs-fonctionnels/demande-de-mot-de-passe
|
||||
# it uses aria-describedby on input and link it to yielded content
|
||||
renders_one :describedby
|
||||
renders_one :label
|
||||
|
||||
def initialize(form:, attribute:, input_type: :text_field, opts: {}, required: true)
|
||||
@form = form
|
||||
|
@ -16,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
|
||||
|
@ -46,7 +51,11 @@ class Dsfr::InputComponent < ApplicationComponent
|
|||
|
||||
# i18n lookups
|
||||
def label
|
||||
object.class.human_attribute_name(@attribute)
|
||||
get_slot(:label).presence || default_label
|
||||
end
|
||||
|
||||
def dsfr_input_classname
|
||||
'fr-input'
|
||||
end
|
||||
|
||||
# kind of input helpers
|
||||
|
@ -63,4 +72,8 @@ class Dsfr::InputComponent < ApplicationComponent
|
|||
end
|
||||
|
||||
private
|
||||
|
||||
def default_label
|
||||
object.class.human_attribute_name(@attribute)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,37 @@
|
|||
module Dsfr
|
||||
module InputErrorable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
delegate :object, to: :@form
|
||||
delegate :errors, to: :object
|
||||
|
||||
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`
|
||||
|
@ -18,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
|
||||
|
@ -67,28 +93,19 @@ 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
|
||||
|
||||
def hint
|
||||
get_slot(:hint).presence || default_hint
|
||||
end
|
||||
|
||||
def default_hint
|
||||
I18n.t("activerecord.attributes.#{object.class.name.underscore}.hints.#{@attribute}")
|
||||
end
|
||||
|
||||
|
@ -101,6 +118,8 @@ module Dsfr
|
|||
end
|
||||
|
||||
def hint?
|
||||
return true if get_slot(:hint).present?
|
||||
|
||||
I18n.exists?("activerecord.attributes.#{object.class.name.underscore}.hints.#{@attribute}")
|
||||
end
|
||||
end
|
||||
|
|
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: "#{code_postal_input_id}-#{value.parameterize}"
|
||||
= @form.label :value, option, for: "#{code_postal_input_id}-#{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,33 @@
|
|||
- 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
|
||||
- elsif @champ.render_as_combobox?
|
||||
= render Dsfr::ComboboxComponent.new form: @form, name: :value, options: @champ.enabled_non_empty_options, selected: @champ.selected, id: @champ.input_id, class: select_class_names, describedby: @champ.describedby_id
|
||||
- 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")
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class Instructeurs::ActivateAccountFormComponent < ApplicationComponent
|
||||
attr_reader :user
|
||||
def initialize(user:)
|
||||
@user = user
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
en:
|
||||
title: Create your account for %{application_name}
|
||||
activate: Activate your account %{email}
|
||||
email_disabled: Instructor email address not changeable
|
||||
submit: Choose password
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
fr:
|
||||
title: Création de compte sur %{application_name}
|
||||
activate: Se créer un compte pour %{email} en choissant un mot de passe
|
||||
email_disabled: Adresse instructeur non modifiable
|
||||
submit: Définir le mot de passe
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
= form_for user, url: { controller: 'users/activate', action: :create }, html: { class: "fr-py-5w" } do |f|
|
||||
|
||||
%h1.fr-h2.fr-mb-7w= t('.title', application_name: APPLICATION_NAME)
|
||||
|
||||
.fr-background-alt--grey.fr-px-12w.fr-py-7w
|
||||
%fieldset.fr-mb-0.fr-fieldset{ aria: { labelledby: 'activate-account-legend' } }
|
||||
|
||||
%legend.fr-fieldset__legend#activate-account-legend
|
||||
%h2.fr-h6.fr-mb-0= t('.activate', email: user.email)
|
||||
|
||||
.fr-fieldset__element
|
||||
%p.fr-text--sm= t('utils.mandatory_champs')
|
||||
|
||||
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { disabled: :disabled, class: 'fr-input-group--disabled', value: t('.email_disabled') })
|
||||
|
||||
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field, opts: { autocomplete: 'current-password' })
|
||||
|
||||
= f.hidden_field :reset_password_token, value: params[:token]
|
||||
|
||||
.fr-fieldset__element
|
||||
.fr-btns-group--right.fr-btns-group.fr-btns-group--inline.fr-btns-group.fr-btns-group--inline
|
||||
%ul
|
||||
%li= f.submit t('.submit'), class: 'fr-mt-2v fr-btn fr-btn'
|
|
@ -3,6 +3,8 @@
|
|||
class Instructeurs::EnConstructionMenuComponent < ApplicationComponent
|
||||
attr_reader :dossier
|
||||
|
||||
delegate :sva_svr_enabled?, to: :"dossier.procedure"
|
||||
|
||||
def initialize(dossier:)
|
||||
@dossier = dossier
|
||||
end
|
||||
|
@ -22,11 +24,11 @@ class Instructeurs::EnConstructionMenuComponent < ApplicationComponent
|
|||
end
|
||||
end
|
||||
|
||||
def sva?
|
||||
dossier.procedure.sva?
|
||||
end
|
||||
|
||||
def sva_resume_method
|
||||
def sva_svr_resume_method
|
||||
dossier.procedure.sva_svr_configuration.resume
|
||||
end
|
||||
|
||||
def sva_svr_human_decision
|
||||
dossier.procedure.sva_svr_configuration.human_decision
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
%h4= t('.request_correction')
|
||||
L’usager sera informé que des modifications sont attendues.
|
||||
|
||||
- if sva?
|
||||
- if sva_resume_method == :reset
|
||||
Le délai du SVA sera réinitialisé lorqu’il déclarera avoir complété le dossier.
|
||||
- if sva_svr_enabled?
|
||||
- if sva_svr_resume_method == :reset
|
||||
Le délai du #{sva_svr_human_decision} sera réinitialisé lorqu’il déclarera avoir complété le dossier.
|
||||
- else
|
||||
Le délai du SVA reprendra lorsqu’il déclarera avoir corrigé le dossier.
|
||||
Le délai du #{sva_svr_human_decision} reprendra lorsqu’il déclarera avoir corrigé le dossier.
|
||||
|
||||
- menu.with_item(class: "inactive form-inside fr-pt-1v") do
|
||||
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier:,
|
||||
|
@ -36,14 +36,14 @@
|
|||
title: 'Marquer en attente de corrections',
|
||||
confirm: 'Envoyer la demande de corrections ?'}
|
||||
|
||||
- if sva?
|
||||
- if sva_svr_enabled?
|
||||
- menu.with_item do
|
||||
= link_to('#', onclick: "DS.showMotivation(event, 'pending_completion');", role: 'menuitem') do
|
||||
%span.fr-icon.fr-icon-error-warning-line.fr-text-default--warning.fr-mt-1v{ "aria-hidden": "true" }
|
||||
|
||||
.dropdown-description
|
||||
%h4= t('.request_completion')
|
||||
L’usager sera informé que son dossier est incomplet. Le délai du SVA sera réinitialisé lorque il déclarera avoir complété le dossier.
|
||||
L’usager sera informé que son dossier est incomplet. Le délai du #{sva_svr_human_decision} sera réinitialisé lorque il déclarera avoir complété le dossier.
|
||||
|
||||
- menu.with_item(class: "inactive form-inside fr-pt-1v") do
|
||||
= render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier:,
|
||||
|
|
|
@ -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
|
||||
|
|