commit
8aa8c4a9de
87 changed files with 1724 additions and 569 deletions
|
@ -23,6 +23,7 @@ module.exports = {
|
||||||
rules: {
|
rules: {
|
||||||
'prettier/prettier': 'error',
|
'prettier/prettier': 'error',
|
||||||
'react-hooks/rules-of-hooks': 'error',
|
'react-hooks/rules-of-hooks': 'error',
|
||||||
|
'react-hooks/exhaustive-deps': 'error',
|
||||||
'react/prop-types': 'off'
|
'react/prop-types': 'off'
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
|
@ -51,7 +52,13 @@ module.exports = {
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'plugin:react-hooks/recommended',
|
'plugin:react-hooks/recommended',
|
||||||
'prettier'
|
'prettier'
|
||||||
]
|
],
|
||||||
|
rules: {
|
||||||
|
'prettier/prettier': 'error',
|
||||||
|
'react-hooks/rules-of-hooks': 'error',
|
||||||
|
'react-hooks/exhaustive-deps': 'error',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'error'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
5
.github/actions/ci-setup-rails/action.yml
vendored
5
.github/actions/ci-setup-rails/action.yml
vendored
|
@ -12,11 +12,12 @@ runs:
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|
||||||
- name: Install Node modules
|
- name: Install Node modules
|
||||||
run: yarn install --frozen-lockfile
|
run: |
|
||||||
|
node --version
|
||||||
|
yarn install --frozen-lockfile
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Setup environment variables
|
- name: Setup environment variables
|
||||||
|
|
1
.node-version
Normal file
1
.node-version
Normal file
|
@ -0,0 +1 @@
|
||||||
|
16.14.0
|
4
Gemfile
4
Gemfile
|
@ -83,7 +83,7 @@ gem 'spreadsheet_architect'
|
||||||
gem 'typhoeus'
|
gem 'typhoeus'
|
||||||
gem 'warden'
|
gem 'warden'
|
||||||
gem 'webpacker'
|
gem 'webpacker'
|
||||||
gem 'zipline', github: 'fringd/zipline', ref: 'd637bbff2' # Unreleased 1.3.0, with a fix for Ruby 3.0 kwargs
|
gem 'zipline'
|
||||||
gem 'zxcvbn-ruby', require: 'zxcvbn'
|
gem 'zxcvbn-ruby', require: 'zxcvbn'
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
|
@ -120,7 +120,7 @@ end
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'graphql-schema_comparator'
|
gem 'graphql-schema_comparator'
|
||||||
gem 'mina', git: 'https://github.com/mina-deploy/mina.git', require: false # Deploy
|
gem 'mina', require: false # Deploy
|
||||||
gem 'pry-byebug' # Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
gem 'pry-byebug' # Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
||||||
gem 'rspec-rails'
|
gem 'rspec-rails'
|
||||||
gem 'simple_xlsx_reader'
|
gem 'simple_xlsx_reader'
|
||||||
|
|
147
Gemfile.lock
147
Gemfile.lock
|
@ -1,60 +1,43 @@
|
||||||
GIT
|
|
||||||
remote: https://github.com/fringd/zipline.git
|
|
||||||
revision: d637bbff262f59718d23a65f50b50163b8ba749f
|
|
||||||
ref: d637bbff2
|
|
||||||
specs:
|
|
||||||
zipline (1.3.0)
|
|
||||||
actionpack (>= 3.2.1, < 7.0)
|
|
||||||
zip_tricks (>= 4.2.1, < 6.0)
|
|
||||||
|
|
||||||
GIT
|
|
||||||
remote: https://github.com/mina-deploy/mina.git
|
|
||||||
revision: 84fa84c7f7f94f9518ef9b7099396ab6676b5881
|
|
||||||
specs:
|
|
||||||
mina (1.2.3)
|
|
||||||
open4 (~> 1.3.4)
|
|
||||||
rake
|
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
aasm (5.2.0)
|
aasm (5.2.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
acsv (0.0.1)
|
acsv (0.0.1)
|
||||||
actioncable (6.1.4.4)
|
actioncable (6.1.4.6)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.4.4)
|
actionmailbox (6.1.4.6)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.4.6)
|
||||||
activejob (= 6.1.4.4)
|
activejob (= 6.1.4.6)
|
||||||
activerecord (= 6.1.4.4)
|
activerecord (= 6.1.4.6)
|
||||||
activestorage (= 6.1.4.4)
|
activestorage (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.4.4)
|
actionmailer (6.1.4.6)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.4.6)
|
||||||
actionview (= 6.1.4.4)
|
actionview (= 6.1.4.6)
|
||||||
activejob (= 6.1.4.4)
|
activejob (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.1.4.4)
|
actionpack (6.1.4.6)
|
||||||
actionview (= 6.1.4.4)
|
actionview (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
rack (~> 2.0, >= 2.0.9)
|
rack (~> 2.0, >= 2.0.9)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.1.4.4)
|
actiontext (6.1.4.6)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.4.6)
|
||||||
activerecord (= 6.1.4.4)
|
activerecord (= 6.1.4.6)
|
||||||
activestorage (= 6.1.4.4)
|
activestorage (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.4.4)
|
actionview (6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
|
@ -72,26 +55,26 @@ GEM
|
||||||
activemodel (>= 5.2.0)
|
activemodel (>= 5.2.0)
|
||||||
activestorage (>= 5.2.0)
|
activestorage (>= 5.2.0)
|
||||||
activesupport (>= 5.2.0)
|
activesupport (>= 5.2.0)
|
||||||
activejob (6.1.4.4)
|
activejob (6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.4.4)
|
activemodel (6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
activerecord (6.1.4.4)
|
activerecord (6.1.4.6)
|
||||||
activemodel (= 6.1.4.4)
|
activemodel (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
activestorage (6.1.4.4)
|
activestorage (6.1.4.6)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.4.6)
|
||||||
activejob (= 6.1.4.4)
|
activejob (= 6.1.4.6)
|
||||||
activerecord (= 6.1.4.4)
|
activerecord (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
marcel (~> 1.0.0)
|
marcel (~> 1.0.0)
|
||||||
mini_mime (>= 1.1.0)
|
mini_mime (>= 1.1.0)
|
||||||
activestorage-openstack (1.5.1)
|
activestorage-openstack (1.5.1)
|
||||||
fog-openstack (~> 1.0)
|
fog-openstack (~> 1.0)
|
||||||
marcel
|
marcel
|
||||||
rails (>= 5.2.2)
|
rails (>= 5.2.2)
|
||||||
activesupport (6.1.4.4)
|
activesupport (6.1.4.6)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
|
@ -183,6 +166,7 @@ GEM
|
||||||
descendants_tracker (~> 0.0.1)
|
descendants_tracker (~> 0.0.1)
|
||||||
concurrent-ruby (1.1.9)
|
concurrent-ruby (1.1.9)
|
||||||
connection_pool (2.2.3)
|
connection_pool (2.2.3)
|
||||||
|
content_disposition (1.0.0)
|
||||||
crack (0.4.5)
|
crack (0.4.5)
|
||||||
rexml
|
rexml
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
|
@ -351,7 +335,7 @@ GEM
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
http_accept_language (2.1.1)
|
http_accept_language (2.1.1)
|
||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
i18n (1.8.11)
|
i18n (1.10.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
i18n-tasks (0.9.33)
|
i18n-tasks (0.9.33)
|
||||||
activesupport (>= 4.0.2)
|
activesupport (>= 4.0.2)
|
||||||
|
@ -417,7 +401,7 @@ GEM
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
logstash-event (1.2.02)
|
logstash-event (1.2.02)
|
||||||
loofah (2.13.0)
|
loofah (2.14.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
|
@ -431,9 +415,12 @@ GEM
|
||||||
mime-types (3.3.1)
|
mime-types (3.3.1)
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2021.0212)
|
mime-types-data (3.2021.0212)
|
||||||
|
mina (1.2.4)
|
||||||
|
open4 (~> 1.3.4)
|
||||||
|
rake
|
||||||
mini_magick (4.11.0)
|
mini_magick (4.11.0)
|
||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.6.1)
|
mini_portile2 (2.7.1)
|
||||||
minitest (5.15.0)
|
minitest (5.15.0)
|
||||||
momentjs-rails (2.20.1)
|
momentjs-rails (2.20.1)
|
||||||
railties (>= 3.1)
|
railties (>= 3.1)
|
||||||
|
@ -444,8 +431,8 @@ GEM
|
||||||
ruby2_keywords (~> 0.0.1)
|
ruby2_keywords (~> 0.0.1)
|
||||||
netrc (0.11.0)
|
netrc (0.11.0)
|
||||||
nio4r (2.5.8)
|
nio4r (2.5.8)
|
||||||
nokogiri (1.12.5)
|
nokogiri (1.13.1)
|
||||||
mini_portile2 (~> 2.6.1)
|
mini_portile2 (~> 2.7.0)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
open4 (1.3.4)
|
open4 (1.3.4)
|
||||||
openid_connect (1.3.0)
|
openid_connect (1.3.0)
|
||||||
|
@ -515,20 +502,20 @@ GEM
|
||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.1.4.4)
|
rails (6.1.4.6)
|
||||||
actioncable (= 6.1.4.4)
|
actioncable (= 6.1.4.6)
|
||||||
actionmailbox (= 6.1.4.4)
|
actionmailbox (= 6.1.4.6)
|
||||||
actionmailer (= 6.1.4.4)
|
actionmailer (= 6.1.4.6)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.4.6)
|
||||||
actiontext (= 6.1.4.4)
|
actiontext (= 6.1.4.6)
|
||||||
actionview (= 6.1.4.4)
|
actionview (= 6.1.4.6)
|
||||||
activejob (= 6.1.4.4)
|
activejob (= 6.1.4.6)
|
||||||
activemodel (= 6.1.4.4)
|
activemodel (= 6.1.4.6)
|
||||||
activerecord (= 6.1.4.4)
|
activerecord (= 6.1.4.6)
|
||||||
activestorage (= 6.1.4.4)
|
activestorage (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.4.4)
|
railties (= 6.1.4.6)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
|
@ -547,9 +534,9 @@ GEM
|
||||||
rails-i18n (6.0.0)
|
rails-i18n (6.0.0)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 6.0.0, < 7)
|
railties (>= 6.0.0, < 7)
|
||||||
railties (6.1.4.4)
|
railties (6.1.4.6)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.4.6)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.4.6)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.13)
|
rake (>= 0.13)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
|
@ -768,8 +755,12 @@ GEM
|
||||||
websocket-extensions (0.1.5)
|
websocket-extensions (0.1.5)
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
zeitwerk (2.5.3)
|
zeitwerk (2.5.4)
|
||||||
zip_tricks (5.6.0)
|
zip_tricks (5.6.0)
|
||||||
|
zipline (1.4.1)
|
||||||
|
actionpack (>= 6.0, < 8.0)
|
||||||
|
content_disposition (~> 1.0)
|
||||||
|
zip_tricks (>= 4.2.1, < 6.0)
|
||||||
zxcvbn-ruby (1.2.0)
|
zxcvbn-ruby (1.2.0)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
|
@ -842,7 +833,7 @@ DEPENDENCIES
|
||||||
lograge
|
lograge
|
||||||
logstash-event
|
logstash-event
|
||||||
mailjet
|
mailjet
|
||||||
mina!
|
mina
|
||||||
openid_connect
|
openid_connect
|
||||||
pg
|
pg
|
||||||
phonelib
|
phonelib
|
||||||
|
@ -892,7 +883,7 @@ DEPENDENCIES
|
||||||
webdrivers (~> 4.0)
|
webdrivers (~> 4.0)
|
||||||
webmock
|
webmock
|
||||||
webpacker
|
webpacker
|
||||||
zipline!
|
zipline
|
||||||
zxcvbn-ruby
|
zxcvbn-ruby
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 12 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 8 KiB After Width: | Height: | Size: 12 KiB |
27
app/assets/stylesheets/agentconnect.scss
Normal file
27
app/assets/stylesheets/agentconnect.scss
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
@import "colors";
|
||||||
|
@import "constants";
|
||||||
|
|
||||||
|
#agentconnect {
|
||||||
|
.agent {
|
||||||
|
color: $blue-france-500;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
background-color: #F2F2F9;
|
||||||
|
padding: $default-padding;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: disc;
|
||||||
|
padding-left: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.citizen {
|
||||||
|
font-size: 16px;
|
||||||
|
color: $blue-france-500;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,17 +3,23 @@
|
||||||
@import "placeholders";
|
@import "placeholders";
|
||||||
@import "mixins";
|
@import "mixins";
|
||||||
|
|
||||||
#auth {
|
#auth,
|
||||||
|
#agentconnect {
|
||||||
// On small screens, hide the procedure description text on auth pages.
|
// On small screens, hide the procedure description text on auth pages.
|
||||||
// It avoids pushing the sign-in/sign-up form out of the viewport.
|
// It avoids pushing the sign-in/sign-up form out of the viewport.
|
||||||
//
|
//
|
||||||
// The procedure description can still be read from the /commencer
|
// The procedure description can still be read from the /commencer
|
||||||
// pages.
|
// pages.
|
||||||
@media (max-width: $two-columns-breakpoint) {
|
@media (max-width: $two-columns-breakpoint) {
|
||||||
.procedure-preview {
|
.procedure-preview,
|
||||||
|
.agent-intro {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
padding-top: 2 * $default-spacer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-form {
|
.auth-form {
|
||||||
|
@ -53,6 +59,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.sign-in-form .form {
|
.sign-in-form .form {
|
||||||
|
input[type="email"] {
|
||||||
|
margin-bottom: $default-padding;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="password"] {
|
input[type="password"] {
|
||||||
margin-bottom: $default-spacer;
|
margin-bottom: $default-spacer;
|
||||||
}
|
}
|
||||||
|
@ -61,3 +71,10 @@
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#session-new {
|
||||||
|
.important-header {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
|
|
||||||
.france-connect-login-button {
|
.france-connect-login-button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 52px;
|
height: 60px;
|
||||||
width: 186px;
|
width: 230px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
background-image: image-url("login-with-fc.svg"), image-url("login-with-fc-hover.svg");
|
background-image: image-url("login-with-fc.svg"), image-url("login-with-fc-hover.svg");
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
@import "constants";
|
|
||||||
|
|
||||||
.m-0 {
|
|
||||||
margin: 0px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-1 {
|
|
||||||
margin-bottom: $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mr-1 {
|
|
||||||
margin-right: $default-spacer !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-4 {
|
|
||||||
margin-bottom: 4 * $default-spacer !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ml-1 {
|
|
||||||
margin-left: $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pl-0 {
|
|
||||||
padding-left: 0px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-0 {
|
|
||||||
padding: 0px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bold {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.numbers-delimiter {
|
|
||||||
display: inline-block;
|
|
||||||
width: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
|
@ -2,38 +2,8 @@
|
||||||
@import "common";
|
@import "common";
|
||||||
@import "constants";
|
@import "constants";
|
||||||
|
|
||||||
.merci {
|
.merci .monavis {
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 60px;
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
margin-top: 4 * $default-padding;
|
margin-top: 2 * $default-padding;
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: (2 * $default-padding) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
b {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send {
|
|
||||||
margin-bottom: 2 * $default-padding;
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: $default-padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.monavis {
|
|
||||||
img {
|
|
||||||
margin-top: 2 * $default-padding;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,12 @@ $procedure-description-line-height: 22px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.small-simple {
|
||||||
|
font-size: 16px;
|
||||||
|
color: $blue-france-500;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.close-procedure {
|
.close-procedure {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
@import "colors";
|
@import "colors";
|
||||||
@import "constants";
|
@import "constants";
|
||||||
|
|
||||||
|
// floats
|
||||||
.pull-left {
|
.pull-left {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +14,9 @@
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// text
|
||||||
|
.text-center,
|
||||||
.center {
|
.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -21,12 +25,21 @@
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.text-sm {
|
||||||
display: none;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.width-100 {
|
.text-lg {
|
||||||
width: 100%;
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.numbers-delimiter {
|
||||||
|
display: inline-block;
|
||||||
|
width: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-text {
|
.empty-text {
|
||||||
|
@ -45,95 +58,42 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// display
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sizing
|
||||||
|
.width-100 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// who known
|
||||||
.highlighted {
|
.highlighted {
|
||||||
background: $orange-bg;
|
background: $orange-bg;
|
||||||
color: $black;
|
color: $black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-sm {
|
// generate spacer utility like bootstrap my-2 -> margin-left/right: 2 * $default-spacer
|
||||||
font-size: 14px;
|
// using $direction.key as css modifier, $direction.values to set css properties
|
||||||
}
|
// scale it using $steps
|
||||||
|
$directions: (
|
||||||
|
"t": ("margin-top"),
|
||||||
|
"r": ("margin-right"),
|
||||||
|
"b": ("margin-bottom"),
|
||||||
|
"l": ("margin-left"),
|
||||||
|
"x": ("margin-left", "margin-right"),
|
||||||
|
"y": ("margin-top", "margin-bottom"),
|
||||||
|
"": ("margin")
|
||||||
|
);
|
||||||
|
$steps: (0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||||
|
|
||||||
.text-lg {
|
@each $modifier, $properties in $directions {
|
||||||
font-size: 18px;
|
@each $step in $steps {
|
||||||
}
|
@each $property in $properties {
|
||||||
|
.m#{$modifier}-#{$step} {
|
||||||
.mt-1 {
|
#{$property}: $step * $default-spacer;
|
||||||
margin-top: $default-spacer;
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.mt-2 {
|
|
||||||
margin-top: 2 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-3 {
|
|
||||||
margin-top: 3 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-4 {
|
|
||||||
margin-top: 4 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-8 {
|
|
||||||
margin-top: 8 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-1 {
|
|
||||||
margin-bottom: $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-2 {
|
|
||||||
margin-bottom: 2 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-3 {
|
|
||||||
margin-bottom: 3 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-4 {
|
|
||||||
margin-bottom: 4 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-8 {
|
|
||||||
margin-bottom: 8 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pt-1 {
|
|
||||||
padding-top: $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pt-2 {
|
|
||||||
padding-top: 2 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pt-3 {
|
|
||||||
padding-top: 3 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pt-4 {
|
|
||||||
padding-top: 4 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pt-8 {
|
|
||||||
padding-top: 8 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pb-1 {
|
|
||||||
padding-bottom: $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pb-2 {
|
|
||||||
padding-bottom: 2 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pb-3 {
|
|
||||||
padding-bottom: 3 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pb-4 {
|
|
||||||
padding-bottom: 4 * $default-spacer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pb-8 {
|
|
||||||
padding-bottom: 8 * $default-spacer;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
module Administrateurs
|
||||||
|
class DossierSubmittedMessagesController < AdministrateurController
|
||||||
|
before_action :retrieve_procedure
|
||||||
|
|
||||||
|
def edit
|
||||||
|
@dossier_submitted_message = build_dossier_submitted_message
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@dossier_submitted_message = build_dossier_submitted_message(dossier_submitted_message_params)
|
||||||
|
|
||||||
|
if @dossier_submitted_message.save
|
||||||
|
redirect_to admin_procedure_path(@procedure), flash: { notice: "Les informations de fin de dépot ont bien été sauvegardées." }
|
||||||
|
else
|
||||||
|
flash.alert = "Impossible de sauvegarder les informations de fin de dépot, veuillez ré-essayer."
|
||||||
|
render :edit, status: 400
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@dossier_submitted_message = build_dossier_submitted_message(dossier_submitted_message_params)
|
||||||
|
if @dossier_submitted_message.save
|
||||||
|
redirect_to admin_procedure_path(@procedure), flash: { notice: "Les informations de fin de dépot ont bien été sauvegardées." }
|
||||||
|
else
|
||||||
|
flash.alert = "Impossible de sauvegarder les informations de \"fin de dépot\", veuillez ré-essayer."
|
||||||
|
render :edit, status: 400
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# for now, only works on active revision no matter the procedure_revision_policy
|
||||||
|
def build_dossier_submitted_message(attributes = {})
|
||||||
|
dossier_submitted_message = @procedure.active_revision.dossier_submitted_message || @procedure.active_revision.build_dossier_submitted_message
|
||||||
|
|
||||||
|
dossier_submitted_message.attributes = attributes unless attributes.empty?
|
||||||
|
dossier_submitted_message
|
||||||
|
end
|
||||||
|
|
||||||
|
def dossier_submitted_message_params
|
||||||
|
params.require(:dossier_submitted_message)
|
||||||
|
.permit(:message_on_submit_by_usager)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -17,7 +17,7 @@ class Champs::SiretController < ApplicationController
|
||||||
|
|
||||||
begin
|
begin
|
||||||
etablissement = find_etablissement_with_siret
|
etablissement = find_etablissement_with_siret
|
||||||
rescue APIEntreprise::API::Error::RequestFailed, APIEntreprise::API::Error::ServiceUnavailable
|
rescue APIEntreprise::API::Error::RequestFailed, APIEntreprise::API::Error::BadGateway, APIEntreprise::API::Error::TimedOut, APIEntreprise::API::Error::ServiceUnavailable
|
||||||
# i18n-tasks-use t('errors.messages.siret_network_error')
|
# i18n-tasks-use t('errors.messages.siret_network_error')
|
||||||
return siret_error(:network_error)
|
return siret_error(:network_error)
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,8 @@ module Experts
|
||||||
end
|
end
|
||||||
|
|
||||||
def procedure
|
def procedure
|
||||||
@procedure = Procedure.find(params[:procedure_id])
|
@procedure = current_expert.procedures.find_by(id: params[:procedure_id])
|
||||||
|
redirect_to(expert_all_avis_path, flash: { alert: "Vous n’avez pas accès à cette démarche." }) and return unless @procedure
|
||||||
expert_avis = current_expert.avis.includes(:dossier).not_hidden_by_administration.where(dossiers: { groupe_instructeur: GroupeInstructeur.where(procedure: @procedure.id) })
|
expert_avis = current_expert.avis.includes(:dossier).not_hidden_by_administration.where(dossiers: { groupe_instructeur: GroupeInstructeur.where(procedure: @procedure.id) })
|
||||||
@avis_a_donner = expert_avis.without_answer
|
@avis_a_donner = expert_avis.without_answer
|
||||||
@avis_donnes = expert_avis.with_answer
|
@avis_donnes = expert_avis.with_answer
|
||||||
|
@ -156,7 +157,8 @@ module Experts
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_avis_and_dossier
|
def set_avis_and_dossier
|
||||||
@avis = Avis.find(params[:id])
|
@avis = current_expert.avis.find_by(id: params[:id])
|
||||||
|
redirect_to(expert_all_avis_path, flash: { alert: "Vous n’avez pas accès à cet avis." }) and return unless @avis
|
||||||
@dossier = @avis.dossier
|
@dossier = @avis.dossier
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ module Users
|
||||||
sanitized_siret = siret_model.siret
|
sanitized_siret = siret_model.siret
|
||||||
begin
|
begin
|
||||||
etablissement = APIEntrepriseService.create_etablissement(@dossier, sanitized_siret, current_user.id)
|
etablissement = APIEntrepriseService.create_etablissement(@dossier, sanitized_siret, current_user.id)
|
||||||
rescue APIEntreprise::API::Error::RequestFailed, APIEntreprise::API::Error::BadGateway, APIEntreprise::API::Error::TimedOut
|
rescue APIEntreprise::API::Error::RequestFailed, APIEntreprise::API::Error::BadGateway, APIEntreprise::API::Error::TimedOut, APIEntreprise::API::Error::ServiceUnavailable
|
||||||
return render_siret_error(t('errors.messages.siret_network_error'))
|
return render_siret_error(t('errors.messages.siret_network_error'))
|
||||||
end
|
end
|
||||||
if etablissement.nil?
|
if etablissement.nil?
|
||||||
|
|
|
@ -26,6 +26,19 @@ import { useDeferredSubmit, useHiddenField } from './shared/hooks';
|
||||||
|
|
||||||
const Context = createContext();
|
const Context = createContext();
|
||||||
|
|
||||||
|
const optionValueByLabel = (values, options, label) => {
|
||||||
|
const maybeOption = values.includes(label)
|
||||||
|
? [label, label]
|
||||||
|
: options.find(([optionLabel]) => optionLabel == label);
|
||||||
|
return maybeOption ? maybeOption[1] : undefined;
|
||||||
|
};
|
||||||
|
const optionLabelByValue = (values, options, value) => {
|
||||||
|
const maybeOption = values.includes(value)
|
||||||
|
? [value, value]
|
||||||
|
: options.find(([, optionValue]) => optionValue == value);
|
||||||
|
return maybeOption ? maybeOption[0] : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
function ComboMultiple({
|
function ComboMultiple({
|
||||||
options,
|
options,
|
||||||
id,
|
id,
|
||||||
|
@ -40,9 +53,6 @@ function ComboMultiple({
|
||||||
invariant(id || label, 'ComboMultiple: `id` or a `label` are required');
|
invariant(id || label, 'ComboMultiple: `id` or a `label` are required');
|
||||||
invariant(group, 'ComboMultiple: `group` is required');
|
invariant(group, 'ComboMultiple: `group` is required');
|
||||||
|
|
||||||
if (!Array.isArray(options[0])) {
|
|
||||||
options = options.filter((o) => o).map((o) => [o, o]);
|
|
||||||
}
|
|
||||||
const inputRef = useRef();
|
const inputRef = useRef();
|
||||||
const [term, setTerm] = useState('');
|
const [term, setTerm] = useState('');
|
||||||
const [selections, setSelections] = useState(selected);
|
const [selections, setSelections] = useState(selected);
|
||||||
|
@ -51,25 +61,22 @@ function ComboMultiple({
|
||||||
const removedLabelledby = `${inputId}-remove`;
|
const removedLabelledby = `${inputId}-remove`;
|
||||||
const selectedLabelledby = `${inputId}-selected`;
|
const selectedLabelledby = `${inputId}-selected`;
|
||||||
|
|
||||||
const optionValueByLabel = (label) => {
|
const optionsWithLabels = useMemo(
|
||||||
const maybeOption = newValues.includes(label)
|
() =>
|
||||||
? [label, label]
|
Array.isArray(options[0])
|
||||||
: options.find(([optionLabel]) => optionLabel == label);
|
? options
|
||||||
return maybeOption ? maybeOption[1] : undefined;
|
: options.filter((o) => o).map((o) => [o, o]),
|
||||||
};
|
[options]
|
||||||
const optionLabelByValue = (value) => {
|
);
|
||||||
const maybeOption = newValues.includes(value)
|
|
||||||
? [value, value]
|
|
||||||
: options.find(([, optionValue]) => optionValue == value);
|
|
||||||
return maybeOption ? maybeOption[0] : undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const extraOptions = useMemo(
|
const extraOptions = useMemo(
|
||||||
() =>
|
() =>
|
||||||
acceptNewValues && term && term.length > 2 && !optionLabelByValue(term)
|
acceptNewValues &&
|
||||||
|
term &&
|
||||||
|
term.length > 2 &&
|
||||||
|
!optionLabelByValue(newValues, optionsWithLabels, term)
|
||||||
? [[term, term]]
|
? [[term, term]]
|
||||||
: [],
|
: [],
|
||||||
[acceptNewValues, term, newValues.join(',')]
|
[acceptNewValues, term, optionsWithLabels, newValues]
|
||||||
);
|
);
|
||||||
const results = useMemo(
|
const results = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
@ -77,12 +84,12 @@ function ComboMultiple({
|
||||||
...extraOptions,
|
...extraOptions,
|
||||||
...(term
|
...(term
|
||||||
? matchSorter(
|
? matchSorter(
|
||||||
options.filter(([label]) => !label.startsWith('--')),
|
optionsWithLabels.filter(([label]) => !label.startsWith('--')),
|
||||||
term
|
term
|
||||||
)
|
)
|
||||||
: options)
|
: optionsWithLabels)
|
||||||
].filter(([, value]) => !selections.includes(value)),
|
].filter(([, value]) => !selections.includes(value)),
|
||||||
[term, selections.join(','), newValues.join(',')]
|
[term, selections, extraOptions, optionsWithLabels]
|
||||||
);
|
);
|
||||||
const [, setHiddenFieldValue, hiddenField] = useHiddenField(group, name);
|
const [, setHiddenFieldValue, hiddenField] = useHiddenField(group, name);
|
||||||
const awaitFormSubmit = useDeferredSubmit(hiddenField);
|
const awaitFormSubmit = useDeferredSubmit(hiddenField);
|
||||||
|
@ -100,7 +107,7 @@ function ComboMultiple({
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelect = (value) => {
|
const onSelect = (value) => {
|
||||||
const maybeValue = [...extraOptions, ...options].find(
|
const maybeValue = [...extraOptions, ...optionsWithLabels].find(
|
||||||
([val]) => val == value
|
([val]) => val == value
|
||||||
);
|
);
|
||||||
const selectedValue = maybeValue && maybeValue[1];
|
const selectedValue = maybeValue && maybeValue[1];
|
||||||
|
@ -128,7 +135,7 @@ function ComboMultiple({
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRemove = (label) => {
|
const onRemove = (label) => {
|
||||||
const optionValue = optionValueByLabel(label);
|
const optionValue = optionValueByLabel(newValues, options, label);
|
||||||
if (optionValue) {
|
if (optionValue) {
|
||||||
saveSelection((selections) =>
|
saveSelection((selections) =>
|
||||||
selections.filter((value) => value != optionValue)
|
selections.filter((value) => value != optionValue)
|
||||||
|
@ -149,7 +156,9 @@ function ComboMultiple({
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
term &&
|
term &&
|
||||||
[...extraOptions, ...options].map(([label]) => label).includes(term)
|
[...extraOptions, ...optionsWithLabels]
|
||||||
|
.map(([label]) => label)
|
||||||
|
.includes(term)
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onSelect(term);
|
onSelect(term);
|
||||||
|
@ -172,7 +181,9 @@ function ComboMultiple({
|
||||||
const onBlur = () => {
|
const onBlur = () => {
|
||||||
const shouldSelect =
|
const shouldSelect =
|
||||||
term &&
|
term &&
|
||||||
[...extraOptions, ...options].map(([label]) => label).includes(term);
|
[...extraOptions, ...optionsWithLabels]
|
||||||
|
.map(([label]) => label)
|
||||||
|
.includes(term);
|
||||||
|
|
||||||
awaitFormSubmit(() => {
|
awaitFormSubmit(() => {
|
||||||
if (shouldSelect) {
|
if (shouldSelect) {
|
||||||
|
@ -199,7 +210,7 @@ function ComboMultiple({
|
||||||
<ComboboxToken
|
<ComboboxToken
|
||||||
key={selection}
|
key={selection}
|
||||||
describedby={removedLabelledby}
|
describedby={removedLabelledby}
|
||||||
value={optionLabelByValue(selection)}
|
value={optionLabelByValue(newValues, options, selection)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useCallback, useRef } from 'react';
|
import React, { useState, useRef, ChangeEventHandler } from 'react';
|
||||||
import { useDebounce } from 'use-debounce';
|
import { useDebounce } from 'use-debounce';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import {
|
import {
|
||||||
|
@ -68,7 +68,7 @@ function ComboSearch<Result>({
|
||||||
const [, value, label] = transformResult(result);
|
const [, value, label] = transformResult(result);
|
||||||
return label ?? value;
|
return label ?? value;
|
||||||
};
|
};
|
||||||
const setExternalValueAndId = useCallback((label: string) => {
|
const setExternalValueAndId = (label: string) => {
|
||||||
const { key, value, result } = resultsMap.current[label];
|
const { key, value, result } = resultsMap.current[label];
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
onChange(value, result);
|
onChange(value, result);
|
||||||
|
@ -76,36 +76,35 @@ function ComboSearch<Result>({
|
||||||
setExternalId(key);
|
setExternalId(key);
|
||||||
setExternalValue(value);
|
setExternalValue(value);
|
||||||
}
|
}
|
||||||
}, []);
|
};
|
||||||
const awaitFormSubmit = useDeferredSubmit(hiddenField);
|
const awaitFormSubmit = useDeferredSubmit(hiddenField);
|
||||||
|
|
||||||
const handleOnChange = useCallback(
|
const handleOnChange: ChangeEventHandler<HTMLInputElement> = ({
|
||||||
({ target: { value } }) => {
|
target: { value }
|
||||||
setValue(value);
|
}) => {
|
||||||
if (!value) {
|
setValue(value);
|
||||||
if (onChange) {
|
if (!value) {
|
||||||
onChange(null);
|
if (onChange) {
|
||||||
} else {
|
onChange(null);
|
||||||
setExternalId('');
|
} else {
|
||||||
setExternalValue('');
|
setExternalId('');
|
||||||
}
|
setExternalValue('');
|
||||||
} else if (value.length >= minimumInputLength) {
|
|
||||||
setSearchTerm(value.trim());
|
|
||||||
if (allowInputValues) {
|
|
||||||
setExternalId('');
|
|
||||||
setExternalValue(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
} else if (value.length >= minimumInputLength) {
|
||||||
[minimumInputLength]
|
setSearchTerm(value.trim());
|
||||||
);
|
if (allowInputValues) {
|
||||||
|
setExternalId('');
|
||||||
|
setExternalValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleOnSelect = useCallback((value: string) => {
|
const handleOnSelect = (value: string) => {
|
||||||
setExternalValueAndId(value);
|
setExternalValueAndId(value);
|
||||||
setValue(value);
|
setValue(value);
|
||||||
setSearchTerm('');
|
setSearchTerm('');
|
||||||
awaitFormSubmit.done();
|
awaitFormSubmit.done();
|
||||||
}, []);
|
};
|
||||||
|
|
||||||
const { isSuccess, data } = useQuery<void, void, unknown, QueryKey>(
|
const { isSuccess, data } = useQuery<void, void, unknown, QueryKey>(
|
||||||
[scope, debouncedSearchTerm, scopeExtra],
|
[scope, debouncedSearchTerm, scopeExtra],
|
||||||
|
@ -117,14 +116,14 @@ function ComboSearch<Result>({
|
||||||
const results =
|
const results =
|
||||||
isSuccess && data ? transformResults(debouncedSearchTerm, data) : [];
|
isSuccess && data ? transformResults(debouncedSearchTerm, data) : [];
|
||||||
|
|
||||||
const onBlur = useCallback(() => {
|
const onBlur = () => {
|
||||||
if (!allowInputValues && isSuccess && results[0]) {
|
if (!allowInputValues && isSuccess && results[0]) {
|
||||||
const label = getLabel(results[0]);
|
const label = getLabel(results[0]);
|
||||||
awaitFormSubmit(() => {
|
awaitFormSubmit(() => {
|
||||||
handleOnSelect(label);
|
handleOnSelect(label);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [data]);
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Combobox onSelect={handleOnSelect}>
|
<Combobox onSelect={handleOnSelect}>
|
||||||
|
|
|
@ -28,35 +28,41 @@ export function CadastreLayer({
|
||||||
const map = useMapLibre();
|
const map = useMapLibre();
|
||||||
const selectedCadastresRef = useRef(new Set<string>());
|
const selectedCadastresRef = useRef(new Set<string>());
|
||||||
|
|
||||||
const highlightFeature = useCallback((cid: string, highlight: boolean) => {
|
const highlightFeature = useCallback(
|
||||||
if (highlight) {
|
(cid: string, highlight: boolean) => {
|
||||||
selectedCadastresRef.current.add(cid);
|
if (highlight) {
|
||||||
} else {
|
selectedCadastresRef.current.add(cid);
|
||||||
selectedCadastresRef.current.delete(cid);
|
} else {
|
||||||
}
|
selectedCadastresRef.current.delete(cid);
|
||||||
if (selectedCadastresRef.current.size == 0) {
|
}
|
||||||
map.setFilter('parcelle-highlighted', ['in', 'id', '']);
|
if (selectedCadastresRef.current.size == 0) {
|
||||||
} else {
|
map.setFilter('parcelle-highlighted', ['in', 'id', '']);
|
||||||
map.setFilter('parcelle-highlighted', [
|
} else {
|
||||||
'in',
|
map.setFilter('parcelle-highlighted', [
|
||||||
'id',
|
'in',
|
||||||
...selectedCadastresRef.current
|
'id',
|
||||||
]);
|
...selectedCadastresRef.current
|
||||||
}
|
]);
|
||||||
}, []);
|
}
|
||||||
|
},
|
||||||
|
[map]
|
||||||
|
);
|
||||||
|
|
||||||
const hoverFeature = useCallback((feature: Feature, hover: boolean) => {
|
const hoverFeature = useCallback(
|
||||||
if (!selectedCadastresRef.current.has(feature.properties?.id)) {
|
(feature: Feature, hover: boolean) => {
|
||||||
map.setFeatureState(
|
if (!selectedCadastresRef.current.has(feature.properties?.id)) {
|
||||||
{
|
map.setFeatureState(
|
||||||
source: 'cadastre',
|
{
|
||||||
sourceLayer: 'parcelles',
|
source: 'cadastre',
|
||||||
id: String(feature.id)
|
sourceLayer: 'parcelles',
|
||||||
},
|
id: String(feature.id)
|
||||||
{ hover }
|
},
|
||||||
);
|
{ hover }
|
||||||
}
|
);
|
||||||
}, []);
|
}
|
||||||
|
},
|
||||||
|
[map]
|
||||||
|
);
|
||||||
|
|
||||||
useCadastres(featureCollection, {
|
useCadastres(featureCollection, {
|
||||||
hoverFeature,
|
hoverFeature,
|
||||||
|
|
|
@ -48,6 +48,8 @@ export function DrawLayer({
|
||||||
trash: true
|
trash: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// We use mapbox-draw plugin with maplibre. They are compatible but types are not.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
map.addControl(draw as any, 'top-left');
|
map.addControl(draw as any, 'top-left');
|
||||||
draw.set(
|
draw.set(
|
||||||
filterFeatureCollection(featureCollection, SOURCE_SELECTION_UTILISATEUR)
|
filterFeatureCollection(featureCollection, SOURCE_SELECTION_UTILISATEUR)
|
||||||
|
@ -64,11 +66,15 @@ export function DrawLayer({
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (drawRef.current) {
|
if (drawRef.current) {
|
||||||
|
// We use mapbox-draw plugin with maplibre. They are compatible but types are not.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
map.removeControl(drawRef.current as any);
|
map.removeControl(drawRef.current as any);
|
||||||
drawRef.current = null;
|
drawRef.current = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [enabled]);
|
// We only want to rerender draw layer on component mount or when the layer is toggled.
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [map, enabled]);
|
||||||
|
|
||||||
const onSetId = useCallback(({ detail }) => {
|
const onSetId = useCallback(({ detail }) => {
|
||||||
drawRef.current?.setFeatureProperty(detail.lid, 'id', detail.id);
|
drawRef.current?.setFeatureProperty(detail.lid, 'id', detail.id);
|
||||||
|
@ -167,7 +173,9 @@ function useExternalEvents(
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fitBounds(featureCollection.bbox as LngLatBoundsLike);
|
fitBounds(featureCollection.bbox as LngLatBoundsLike);
|
||||||
}, []);
|
// We only want to zoom on bbox on component mount.
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [fitBounds]);
|
||||||
|
|
||||||
useEvent('map:feature:focus', onFeatureFocus);
|
useEvent('map:feature:focus', onFeatureFocus);
|
||||||
useEvent('map:feature:create', onFeatureCreate);
|
useEvent('map:feature:create', onFeatureCreate);
|
||||||
|
|
|
@ -44,13 +44,13 @@ export function GeoJSONLayer({
|
||||||
popup.remove();
|
popup.remove();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[popup]
|
[map, popup]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onMouseLeave = useCallback(() => {
|
const onMouseLeave = useCallback(() => {
|
||||||
map.getCanvas().style.cursor = '';
|
map.getCanvas().style.cursor = '';
|
||||||
popup.remove();
|
popup.remove();
|
||||||
}, [popup]);
|
}, [map, popup]);
|
||||||
|
|
||||||
useExternalEvents(featureCollection);
|
useExternalEvents(featureCollection);
|
||||||
|
|
||||||
|
@ -99,17 +99,22 @@ export function GeoJSONLayer({
|
||||||
|
|
||||||
function useExternalEvents(featureCollection: FeatureCollection) {
|
function useExternalEvents(featureCollection: FeatureCollection) {
|
||||||
const fitBounds = useFitBounds();
|
const fitBounds = useFitBounds();
|
||||||
const onFeatureFocus = useCallback(({ detail }) => {
|
const onFeatureFocus = useCallback(
|
||||||
const { id } = detail;
|
({ detail }) => {
|
||||||
const feature = findFeature(featureCollection, id);
|
const { id } = detail;
|
||||||
if (feature) {
|
const feature = findFeature(featureCollection, id);
|
||||||
fitBounds(getBounds(feature.geometry));
|
if (feature) {
|
||||||
}
|
fitBounds(getBounds(feature.geometry));
|
||||||
}, []);
|
}
|
||||||
|
},
|
||||||
|
[featureCollection, fitBounds]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fitBounds(featureCollection.bbox as LngLatBoundsLike);
|
fitBounds(featureCollection.bbox as LngLatBoundsLike);
|
||||||
}, []);
|
// We only want to zoom on bbox on component mount.
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [fitBounds]);
|
||||||
|
|
||||||
useEvent('map:feature:focus', onFeatureFocus);
|
useEvent('map:feature:focus', onFeatureFocus);
|
||||||
}
|
}
|
||||||
|
@ -139,7 +144,7 @@ function LineStringLayer({
|
||||||
type: 'line',
|
type: 'line',
|
||||||
paint: lineStringSelectionLine
|
paint: lineStringSelectionLine
|
||||||
});
|
});
|
||||||
}, []);
|
}, [map, layerId, sourceId, feature]);
|
||||||
|
|
||||||
useMapEvent('mouseenter', onMouseEnter, layerId);
|
useMapEvent('mouseenter', onMouseEnter, layerId);
|
||||||
useMapEvent('mouseleave', onMouseLeave, layerId);
|
useMapEvent('mouseleave', onMouseLeave, layerId);
|
||||||
|
@ -172,7 +177,7 @@ function PointLayer({
|
||||||
type: 'circle',
|
type: 'circle',
|
||||||
paint: pointSelectionCircle
|
paint: pointSelectionCircle
|
||||||
});
|
});
|
||||||
}, []);
|
}, [map, layerId, sourceId, feature]);
|
||||||
|
|
||||||
useMapEvent('mouseenter', onMouseEnter, layerId);
|
useMapEvent('mouseenter', onMouseEnter, layerId);
|
||||||
useMapEvent('mouseleave', onMouseLeave, layerId);
|
useMapEvent('mouseleave', onMouseLeave, layerId);
|
||||||
|
@ -212,7 +217,7 @@ function PolygonLayer({
|
||||||
type: 'fill',
|
type: 'fill',
|
||||||
paint: polygonSelectionFill
|
paint: polygonSelectionFill
|
||||||
});
|
});
|
||||||
}, []);
|
}, [map, layerId, lineLayerId, sourceId, feature]);
|
||||||
|
|
||||||
useMapEvent('mouseenter', onMouseEnter, layerId);
|
useMapEvent('mouseenter', onMouseEnter, layerId);
|
||||||
useMapEvent('mouseleave', onMouseLeave, layerId);
|
useMapEvent('mouseleave', onMouseLeave, layerId);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
import invariant from 'tiny-invariant';
|
||||||
|
|
||||||
export function FlashMessage({
|
export function FlashMessage({
|
||||||
message,
|
message,
|
||||||
|
@ -12,11 +13,13 @@ export function FlashMessage({
|
||||||
sticky?: boolean;
|
sticky?: boolean;
|
||||||
fixed?: boolean;
|
fixed?: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
const element = document.getElementById('flash_messages');
|
||||||
|
invariant(element, 'Flash messages root element not found');
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<div className="flash_message center">
|
<div className="flash_message center">
|
||||||
<div className={flashClassName(level, sticky, fixed)}>{message}</div>
|
<div className={flashClassName(level, sticky, fixed)}>{message}</div>
|
||||||
</div>,
|
</div>,
|
||||||
document.getElementById('flash_messages')!
|
element
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ import React, {
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
ReactNode,
|
ReactNode,
|
||||||
createContext
|
createContext,
|
||||||
|
useCallback
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import maplibre, { Map, Style, NavigationControl } from 'maplibre-gl';
|
import maplibre, { Map, Style, NavigationControl } from 'maplibre-gl';
|
||||||
|
|
||||||
|
@ -37,11 +38,14 @@ export function MapLibre({ children, header, footer, layers }: MapLibreProps) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [map, setMap] = useState<Map | null>();
|
const [map, setMap] = useState<Map | null>();
|
||||||
|
|
||||||
const onStyleChange = (style: Style) => {
|
const onStyleChange = useCallback(
|
||||||
if (map) {
|
(style: Style) => {
|
||||||
map.setStyle(style);
|
if (map) {
|
||||||
}
|
map.setStyle(style);
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
[map]
|
||||||
|
);
|
||||||
const { style, ...mapStyleProps } = useStyle(layers, onStyleChange);
|
const { style, ...mapStyleProps } = useStyle(layers, onStyleChange);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -56,7 +60,7 @@ export function MapLibre({ children, header, footer, layers }: MapLibreProps) {
|
||||||
setMap(map);
|
setMap(map);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, []);
|
}, [map, style, isSupported]);
|
||||||
|
|
||||||
if (!isSupported) {
|
if (!isSupported) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -12,16 +12,22 @@ import { useMapLibre } from './MapLibre';
|
||||||
|
|
||||||
export function useFitBounds() {
|
export function useFitBounds() {
|
||||||
const map = useMapLibre();
|
const map = useMapLibre();
|
||||||
return useCallback((bbox: LngLatBoundsLike) => {
|
return useCallback(
|
||||||
map.fitBounds(bbox, { padding: 100 });
|
(bbox: LngLatBoundsLike) => {
|
||||||
}, []);
|
map.fitBounds(bbox, { padding: 100 });
|
||||||
|
},
|
||||||
|
[map]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useFlyTo() {
|
export function useFlyTo() {
|
||||||
const map = useMapLibre();
|
const map = useMapLibre();
|
||||||
return useCallback((zoom: number, center: [number, number]) => {
|
return useCallback(
|
||||||
map.flyTo({ zoom, center });
|
(zoom: number, center: [number, number]) => {
|
||||||
}, []);
|
map.flyTo({ zoom, center });
|
||||||
|
},
|
||||||
|
[map]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useEvent(eventName: string, callback: EventListener) {
|
export function useEvent(eventName: string, callback: EventListener) {
|
||||||
|
@ -44,12 +50,16 @@ export function useMapEvent(
|
||||||
const map = useMapLibre();
|
const map = useMapLibre();
|
||||||
return useEffect(() => {
|
return useEffect(() => {
|
||||||
if (target) {
|
if (target) {
|
||||||
|
// event typing is hard
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
map.on(eventName as keyof MapLayerEventType, target, callback as any);
|
map.on(eventName as keyof MapLayerEventType, target, callback as any);
|
||||||
} else {
|
} else {
|
||||||
map.on(eventName, callback);
|
map.on(eventName, callback);
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (target) {
|
if (target) {
|
||||||
|
// event typing is hard
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
map.off(eventName as keyof MapLayerEventType, target, callback as any);
|
map.off(eventName as keyof MapLayerEventType, target, callback as any);
|
||||||
} else {
|
} else {
|
||||||
map.off(eventName, callback);
|
map.off(eventName, callback);
|
||||||
|
@ -104,7 +114,7 @@ export function useStyle(
|
||||||
[styleId, enabledLayers]
|
[styleId, enabledLayers]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => onStyleChange(style), [style]);
|
useEffect(() => onStyleChange(style), [onStyleChange, style]);
|
||||||
|
|
||||||
return { style, layers, setStyle, setLayerEnabled, setLayerOpacity };
|
return { style, layers, setStyle, setLayerEnabled, setLayerOpacity };
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import type { AnyLayer } from 'maplibre-gl';
|
import type { AnyLayer } from 'maplibre-gl';
|
||||||
|
|
||||||
const layers: AnyLayer[] = [
|
const layers: AnyLayer[] = [
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import type { AnyLayer } from 'maplibre-gl';
|
import type { AnyLayer } from 'maplibre-gl';
|
||||||
|
|
||||||
const layers: AnyLayer[] = [
|
const layers: AnyLayer[] = [
|
||||||
|
|
|
@ -2,6 +2,17 @@ import { QueryClient, QueryFunction } from 'react-query';
|
||||||
import { getJSON, isNumeric } from '@utils';
|
import { getJSON, isNumeric } from '@utils';
|
||||||
import { matchSorter } from 'match-sorter';
|
import { matchSorter } from 'match-sorter';
|
||||||
|
|
||||||
|
type Gon = {
|
||||||
|
gon: {
|
||||||
|
autocomplete?: {
|
||||||
|
api_geo_url?: string;
|
||||||
|
api_adresse_url?: string;
|
||||||
|
api_education_url?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
declare const window: Window & typeof globalThis & Gon;
|
||||||
|
|
||||||
const API_EDUCATION_QUERY_LIMIT = 5;
|
const API_EDUCATION_QUERY_LIMIT = 5;
|
||||||
const API_GEO_QUERY_LIMIT = 5;
|
const API_GEO_QUERY_LIMIT = 5;
|
||||||
const API_ADRESSE_QUERY_LIMIT = 5;
|
const API_ADRESSE_QUERY_LIMIT = 5;
|
||||||
|
@ -16,7 +27,7 @@ const API_ADRESSE_QUERY_LIMIT = 5;
|
||||||
const API_GEO_COMMUNES_QUERY_LIMIT = 60;
|
const API_GEO_COMMUNES_QUERY_LIMIT = 60;
|
||||||
|
|
||||||
const { api_geo_url, api_adresse_url, api_education_url } =
|
const { api_geo_url, api_adresse_url, api_education_url } =
|
||||||
(window as any).gon.autocomplete || {};
|
window.gon.autocomplete || {};
|
||||||
|
|
||||||
type QueryKey = readonly [
|
type QueryKey = readonly [
|
||||||
scope: string,
|
scope: string,
|
||||||
|
@ -70,8 +81,9 @@ const defaultQueryFn: QueryFunction<unknown, QueryKey> = async ({
|
||||||
}
|
}
|
||||||
throw new Error(`Error fetching from "${scope}" API`);
|
throw new Error(`Error fetching from "${scope}" API`);
|
||||||
});
|
});
|
||||||
(promise as any).cancel = () => controller && controller.abort();
|
return Object.assign(promise, {
|
||||||
return promise;
|
cancel: () => controller && controller.abort()
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let paysCache: { label: string }[];
|
let paysCache: { label: string }[];
|
||||||
|
@ -85,6 +97,8 @@ async function getPays(): Promise<{ label: string }[]> {
|
||||||
export const queryClient = new QueryClient({
|
export const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
|
// we don't really care about global queryFn type
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
queryFn: defaultQueryFn as any
|
queryFn: defaultQueryFn as any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,15 @@ export function ajax(options: Rails.AjaxOptions) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ResponseError extends Error {
|
||||||
|
response: Response;
|
||||||
|
|
||||||
|
constructor(response: Response) {
|
||||||
|
super(String(response.statusText || response.status));
|
||||||
|
this.response = response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getJSON(url: string, data: unknown, method = 'GET') {
|
export function getJSON(url: string, data: unknown, method = 'GET') {
|
||||||
const { query, ...options } = fetchOptions(data, method);
|
const { query, ...options } = fetchOptions(data, method);
|
||||||
|
|
||||||
|
@ -98,9 +107,7 @@ export function getJSON(url: string, data: unknown, method = 'GET') {
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
const error = new Error(String(response.statusText || response.status));
|
throw new ResponseError(response);
|
||||||
(error as any).response = response;
|
|
||||||
throw error;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,8 +132,9 @@ export function on(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNumeric(n: string) {
|
export function isNumeric(s: string) {
|
||||||
return !isNaN(parseFloat(n)) && isFinite(n as any as number);
|
const n = parseFloat(s);
|
||||||
|
return !isNaN(n) && isFinite(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
function offset(element: HTMLElement) {
|
function offset(element: HTMLElement) {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
# data :jsonb
|
# data :jsonb
|
||||||
# fetch_external_data_exceptions :string is an Array
|
# fetch_external_data_exceptions :string is an Array
|
||||||
# private :boolean default(FALSE), not null
|
# private :boolean default(FALSE), not null
|
||||||
|
# rebased_at :datetime
|
||||||
# row :integer
|
# row :integer
|
||||||
# type :string
|
# type :string
|
||||||
# value :string
|
# value :string
|
||||||
|
|
|
@ -2,19 +2,57 @@ module DossierRebaseConcern
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
def rebase!
|
def rebase!
|
||||||
if brouillon? && revision != procedure.published_revision
|
if can_rebase?
|
||||||
transaction do
|
transaction do
|
||||||
rebase
|
rebase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_rebase?
|
||||||
|
revision != procedure.published_revision &&
|
||||||
|
(brouillon? || accepted_en_construction_changes? || accepted_en_instruction_changes?)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pending_changes
|
||||||
|
revision.compare(procedure.published_revision)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def accepted_en_construction_changes?
|
||||||
|
en_construction? && pending_changes.all? { |change| accepted_en_construction_change?(change) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def accepted_en_instruction_changes?
|
||||||
|
en_instruction? && pending_changes.all? { |change| accepted_en_instruction_change?(change) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def accepted_en_construction_change?(change)
|
||||||
|
if change[:model] == :attestation_template || change[:op] == :move || change[:op] == :remove
|
||||||
|
true
|
||||||
|
elsif change[:op] == :update
|
||||||
|
case change[:attribute]
|
||||||
|
when :carte_layers
|
||||||
|
true
|
||||||
|
when :mandatory
|
||||||
|
change[:from] && !change[:to]
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def accepted_en_instruction_change?(change)
|
||||||
|
change[:model] == :attestation_template
|
||||||
|
end
|
||||||
|
|
||||||
def rebase
|
def rebase
|
||||||
attachments_to_purge = []
|
attachments_to_purge = []
|
||||||
geo_areas_to_delete = []
|
geo_areas_to_delete = []
|
||||||
changes_by_type_de_champ = revision.compare(procedure.published_revision)
|
changes_by_type_de_champ = pending_changes
|
||||||
.filter { |change| change[:model] == :type_de_champ }
|
.filter { |change| change[:model] == :type_de_champ }
|
||||||
.group_by { |change| change[:stable_id] }
|
.group_by { |change| change[:stable_id] }
|
||||||
|
|
||||||
|
@ -51,7 +89,9 @@ module DossierRebaseConcern
|
||||||
when :drop_down_options
|
when :drop_down_options
|
||||||
update[:value] = nil
|
update[:value] = nil
|
||||||
when :carte_layers
|
when :carte_layers
|
||||||
geo_areas_to_delete += champ.geo_areas
|
if change[:from].include?(:cadastres) && !change[:to].include?(:cadastres)
|
||||||
|
geo_areas_to_delete += champ.cadastres
|
||||||
|
end
|
||||||
end
|
end
|
||||||
update[:rebased_at] = Time.zone.now
|
update[:rebased_at] = Time.zone.now
|
||||||
end
|
end
|
||||||
|
|
12
app/models/dossier_submitted_message.rb
Normal file
12
app/models/dossier_submitted_message.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: dossier_submitted_messages
|
||||||
|
#
|
||||||
|
# id :bigint not null, primary key
|
||||||
|
# message_on_submit_by_usager :string
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
class DossierSubmittedMessage < ApplicationRecord
|
||||||
|
has_many :revisions, class_name: 'ProcedureRevision', inverse_of: :dossier_submitted_message, dependent: :nullify
|
||||||
|
end
|
|
@ -18,7 +18,6 @@
|
||||||
# description :string
|
# description :string
|
||||||
# direction :string
|
# direction :string
|
||||||
# duree_conservation_dossiers_dans_ds :integer
|
# duree_conservation_dossiers_dans_ds :integer
|
||||||
# duree_conservation_dossiers_hors_ds :integer
|
|
||||||
# durees_conservation_required :boolean default(TRUE)
|
# durees_conservation_required :boolean default(TRUE)
|
||||||
# encrypted_api_particulier_token :string
|
# encrypted_api_particulier_token :string
|
||||||
# euro_flag :boolean default(FALSE)
|
# euro_flag :boolean default(FALSE)
|
||||||
|
@ -80,6 +79,10 @@ class Procedure < ApplicationRecord
|
||||||
has_one :draft_attestation_template, through: :draft_revision, source: :attestation_template
|
has_one :draft_attestation_template, through: :draft_revision, source: :attestation_template
|
||||||
has_one :published_attestation_template, through: :published_revision, source: :attestation_template
|
has_one :published_attestation_template, through: :published_revision, source: :attestation_template
|
||||||
|
|
||||||
|
has_one :published_dossier_submitted_message, dependent: :destroy, through: :published_revision, source: :dossier_submitted_message
|
||||||
|
has_one :draft_dossier_submitted_message, dependent: :destroy, through: :draft_revision, source: :dossier_submitted_message
|
||||||
|
has_many :dossier_submitted_messages, through: :revisions, source: :dossier_submitted_message
|
||||||
|
|
||||||
has_many :experts_procedures, dependent: :destroy
|
has_many :experts_procedures, dependent: :destroy
|
||||||
has_many :experts, through: :experts_procedures
|
has_many :experts, through: :experts_procedures
|
||||||
|
|
||||||
|
@ -92,6 +95,10 @@ class Procedure < ApplicationRecord
|
||||||
belongs_to :service, optional: true
|
belongs_to :service, optional: true
|
||||||
belongs_to :zone, optional: true
|
belongs_to :zone, optional: true
|
||||||
|
|
||||||
|
def active_dossier_submitted_message
|
||||||
|
published_dossier_submitted_message || draft_dossier_submitted_message
|
||||||
|
end
|
||||||
|
|
||||||
def active_revision
|
def active_revision
|
||||||
brouillon? ? draft_revision : published_revision
|
brouillon? ? draft_revision : published_revision
|
||||||
end
|
end
|
||||||
|
@ -441,7 +448,8 @@ class Procedure < ApplicationRecord
|
||||||
revision_types_de_champ_private: {
|
revision_types_de_champ_private: {
|
||||||
type_de_champ: :types_de_champ
|
type_de_champ: :types_de_champ
|
||||||
},
|
},
|
||||||
attestation_template: []
|
attestation_template: [],
|
||||||
|
dossier_submitted_message: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
include_list[:groupe_instructeurs] = :instructeurs if !is_different_admin
|
include_list[:groupe_instructeurs] = :instructeurs if !is_different_admin
|
||||||
|
@ -738,9 +746,9 @@ class Procedure < ApplicationRecord
|
||||||
def publish_revision!
|
def publish_revision!
|
||||||
update!(draft_revision: create_new_revision, published_revision: draft_revision)
|
update!(draft_revision: create_new_revision, published_revision: draft_revision)
|
||||||
published_revision.touch(:published_at)
|
published_revision.touch(:published_at)
|
||||||
dossiers.state_brouillon.find_each do |dossier|
|
dossiers
|
||||||
DossierRebaseJob.perform_later(dossier)
|
.state_not_termine
|
||||||
end
|
.find_each { |dossier| DossierRebaseJob.perform_later(dossier) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def cnaf_enabled?
|
def cnaf_enabled?
|
||||||
|
|
|
@ -7,12 +7,14 @@
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# attestation_template_id :bigint
|
# attestation_template_id :bigint
|
||||||
# procedure_id :bigint not null
|
# dossier_submitted_message_id :bigint
|
||||||
|
# procedure_id :bigint not null
|
||||||
#
|
#
|
||||||
class ProcedureRevision < ApplicationRecord
|
class ProcedureRevision < ApplicationRecord
|
||||||
self.implicit_order_column = :created_at
|
self.implicit_order_column = :created_at
|
||||||
belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions, optional: false
|
belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions, optional: false
|
||||||
belongs_to :attestation_template, inverse_of: :revisions, optional: true, dependent: :destroy
|
belongs_to :attestation_template, inverse_of: :revisions, optional: true, dependent: :destroy
|
||||||
|
belongs_to :dossier_submitted_message, inverse_of: :revisions, optional: true, dependent: :destroy
|
||||||
|
|
||||||
has_many :dossiers, inverse_of: :revision, foreign_key: :revision_id
|
has_many :dossiers, inverse_of: :revision, foreign_key: :revision_id
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Table name: zones
|
# Table name: zones
|
||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# acronym :string
|
# acronym :string not null
|
||||||
# label :string
|
# label :string
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
= f.label :message_on_submit_by_usager do
|
||||||
|
Message affiché après l'envoie du dossier
|
||||||
|
= f.text_area :message_on_submit_by_usager, placeholder: "Merci votre dossier sera traité dans les plus bref delais"
|
|
@ -0,0 +1,34 @@
|
||||||
|
- content_for(:root_class, 'scroll-margins-for-sticky-footer')
|
||||||
|
|
||||||
|
= render partial: 'administrateurs/breadcrumbs',
|
||||||
|
locals: { steps: [link_to('Démarches', admin_procedures_path),
|
||||||
|
link_to(@procedure.libelle, admin_procedure_path(@procedure)),
|
||||||
|
'Fin de dépot'] }
|
||||||
|
|
||||||
|
.procedure-form
|
||||||
|
.procedure-form__columns.container
|
||||||
|
= form_for @dossier_submitted_message,
|
||||||
|
url: url_for({ controller: 'administrateurs/dossier_submitted_messages', action: :update, id: @procedure.id }),
|
||||||
|
html: { class: 'form procedure-form__column--form' } do |f|
|
||||||
|
|
||||||
|
%h1.page-title
|
||||||
|
Fin du dépot
|
||||||
|
%p.notice
|
||||||
|
L'utilisateur se vera afficher ce message une fois le dossier envoyé
|
||||||
|
|
||||||
|
= render partial: 'administrateurs/dossier_submitted_messages/informations', locals: { f: f }
|
||||||
|
|
||||||
|
|
||||||
|
.procedure-form__actions
|
||||||
|
.actions-left
|
||||||
|
= f.submit 'Enregistrer', class: 'button primary send'
|
||||||
|
|
||||||
|
.procedure-form__column--preview
|
||||||
|
%h3
|
||||||
|
.procedure-form__preview-title
|
||||||
|
Aperçu
|
||||||
|
.notice
|
||||||
|
Cet aperçu est mis à jour après chaque sauvegarde.
|
||||||
|
|
||||||
|
.procedure-preview
|
||||||
|
= render partial: 'users/dossiers/merci', locals: { procedure: @procedure, dossier: nil}
|
|
@ -234,3 +234,18 @@
|
||||||
%p.card-admin-title MonAvis
|
%p.card-admin-title MonAvis
|
||||||
%p.card-admin-subtitle Avis des usagers sur votre démarche
|
%p.card-admin-subtitle Avis des usagers sur votre démarche
|
||||||
%p.button Modifier
|
%p.button Modifier
|
||||||
|
|
||||||
|
= link_to edit_admin_procedure_dossier_submitted_message_path(@procedure), class: 'card-admin' do
|
||||||
|
- if @procedure.active_dossier_submitted_message.present?
|
||||||
|
%div
|
||||||
|
%span.icon.accept
|
||||||
|
%p.card-admin-status-accept Validé
|
||||||
|
- else
|
||||||
|
%div
|
||||||
|
%span.icon.clock
|
||||||
|
%p.card-admin-status-todo À configurer
|
||||||
|
%div
|
||||||
|
%p.card-admin-title Fin de dépot
|
||||||
|
%p.card-admin-subtitle Orienter l'usager suite à l'envoie de son dossier
|
||||||
|
%p.button Modifier
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,45 @@
|
||||||
- content_for(:title, t('.cta'))
|
- content_for(:title, t('.cta'))
|
||||||
|
|
||||||
.container
|
#agentconnect
|
||||||
%h1.mt-2.mb-2= t('.connect')
|
.two-columns
|
||||||
|
.columns-container
|
||||||
|
.column.agent-intro
|
||||||
|
%h1.mt-2.mb-2.agent= t('.you_are_an_agent')
|
||||||
|
.box= t('.in_progress_html')
|
||||||
|
|
||||||
%p= t('.intro_html', app_name: APPLICATION_NAME)
|
.center.mt-2
|
||||||
|
%span.citizen= t('.you_are_a_citizen')
|
||||||
|
%br
|
||||||
|
%br
|
||||||
|
= link_to t('.citizen_page'), new_user_session_path, class: "button expend secondary"
|
||||||
|
|
||||||
= link_to t('.cta'), agent_connect_login_path, class: "france-connect-agent-login-button"
|
.column
|
||||||
|
= t('.connect_html')
|
||||||
|
|
||||||
|
= link_to t('.cta'), agent_connect_login_path, class: "france-connect-agent-login-button"
|
||||||
|
.france-connect-help-link
|
||||||
|
= link_to t('.whats_agentconnect'), 'https://agentconnect.gouv.fr/', class: 'link', target: '_blank', target: "_blank", rel: "noopener", class: "link"
|
||||||
|
|
||||||
|
.france-connect-login-separator
|
||||||
|
= t('views.shared.france_connect_login.separator')
|
||||||
|
|
||||||
|
#session-new.auth-form.sign-in-form
|
||||||
|
= form_for User.new, url: user_session_path, html: { class: "form" } do |f|
|
||||||
|
= f.label :email, t('.pro_email')
|
||||||
|
= f.text_field :email, type: :email, autocomplete: 'username', autofocus: true
|
||||||
|
|
||||||
|
= f.label :password, t('views.users.sessions.new.password', min_length: PASSWORD_MIN_LENGTH)
|
||||||
|
= f.password_field :password, autocomplete: 'current-password'
|
||||||
|
|
||||||
|
.auth-options
|
||||||
|
.flex-no-shrink
|
||||||
|
= f.check_box :remember_me
|
||||||
|
= f.label :remember_me, t('views.users.sessions.new.remember_me'), class: 'remember-me'
|
||||||
|
|
||||||
|
.text-right
|
||||||
|
= link_to t('views.users.sessions.new.reset_password'), new_user_password_path, class: "link"
|
||||||
|
|
||||||
|
= f.submit t('views.users.sessions.new.connection'), class: "button large primary expand"
|
||||||
|
|
||||||
|
- content_for :footer do
|
||||||
|
= render partial: 'users/dossiers/index_footer'
|
||||||
|
|
|
@ -3,16 +3,19 @@
|
||||||
|
|
||||||
%p= t(:hello, scope: [:views, :shared, :greetings])
|
%p= t(:hello, scope: [:views, :shared, :greetings])
|
||||||
|
|
||||||
- if !@dossier.brouillon?
|
- if @dossier.brouillon?
|
||||||
%p= t('.body_html', libelle_demarche: @dossier.procedure.libelle)
|
|
||||||
%p= t('.link')
|
|
||||||
= round_button(t('.access_message'), messagerie_dossier_url(@dossier), :primary)
|
|
||||||
- else
|
|
||||||
%p= t('.body_draft_html', libelle_demarche: @dossier.procedure.libelle)
|
%p= t('.body_draft_html', libelle_demarche: @dossier.procedure.libelle)
|
||||||
%p{ style: "padding: 8px; color: #333333; background-color: #EEEEEE; font-size: 14px;" }
|
%p{ style: "padding: 8px; color: #333333; background-color: #EEEEEE; font-size: 14px;" }
|
||||||
= @body
|
= @body
|
||||||
%p= t('.contact')
|
- if @service&.email.present?
|
||||||
|
%p= t('.contact_html', email: @service.email)
|
||||||
|
- else
|
||||||
|
%p= t('.contact_no_email')
|
||||||
= round_button(t('.access_file'), dossier_url(@dossier), :primary)
|
= round_button(t('.access_file'), dossier_url(@dossier), :primary)
|
||||||
|
- else
|
||||||
|
%p= t('.body_html', libelle_demarche: @dossier.procedure.libelle)
|
||||||
|
%p= t('.link')
|
||||||
|
= round_button(t('.access_message'), messagerie_dossier_url(@dossier), :primary)
|
||||||
|
|
||||||
= render 'layouts/mailers/signature', service: @service
|
= render 'layouts/mailers/signature', service: @service
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
%li
|
%li
|
||||||
= render partial: 'layouts/account_dropdown', locals: { nav_bar_profile: nav_bar_profile }
|
= render partial: 'layouts/account_dropdown', locals: { nav_bar_profile: nav_bar_profile }
|
||||||
|
|
||||||
- elsif request.path != new_user_session_path
|
- elsif (request.path != new_user_session_path && request.path != agent_connect_path)
|
||||||
- if request.path == new_user_registration_path
|
- if request.path == new_user_registration_path
|
||||||
%li
|
%li
|
||||||
= t('views.shared.account.already_user_question')
|
= t('views.shared.account.already_user_question')
|
||||||
|
|
|
@ -7,3 +7,8 @@
|
||||||
= t('.line2')
|
= t('.line2')
|
||||||
%br
|
%br
|
||||||
= t('.line3')
|
= t('.line3')
|
||||||
|
%hr
|
||||||
|
%span.small-simple= t('.are_you_new', app_name: APPLICATION_NAME.gsub("-","‑")).html_safe
|
||||||
|
%br
|
||||||
|
%br
|
||||||
|
= link_to t('views.users.sessions.new.find_procedure'), COMMENT_TROUVER_MA_DEMARCHE_URL, target: "_blank", class: "button expend secondary"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
- if FranceConnectService.enabled?
|
- if FranceConnectService.enabled?
|
||||||
.france-connect-login
|
.france-connect-login
|
||||||
%h2
|
%h2.important-header
|
||||||
= t('views.shared.france_connect_login.title')
|
= t('views.shared.france_connect_login.title')
|
||||||
%p
|
%p
|
||||||
= t('views.shared.france_connect_login.description')
|
= t('views.shared.france_connect_login.description')
|
||||||
|
|
26
app/views/users/dossiers/_merci.html.haml
Normal file
26
app/views/users/dossiers/_merci.html.haml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
.merci.text-center.mb-7
|
||||||
|
.container
|
||||||
|
= image_tag('user/envoi-dossier.svg', alt: '', class: 'mt-8')
|
||||||
|
%h1.mt-4.mb-3.mx-0= t('views.users.dossiers.merci.thanks')
|
||||||
|
%p.send.m-2.text-lg
|
||||||
|
= t('views.users.dossiers.merci.dossier_send_l1')
|
||||||
|
%strong= procedure.libelle
|
||||||
|
= t('views.users.dossiers.merci.dossier_send_l2')
|
||||||
|
%p.m-2
|
||||||
|
= t('views.users.dossiers.merci.dossier_acces_l1')
|
||||||
|
%strong= t('views.users.dossiers.merci.dossier_acces_l2')
|
||||||
|
%p.m-2
|
||||||
|
= t('views.users.dossiers.merci.dossier_edit_l1')
|
||||||
|
- if !dossier&.read_only?
|
||||||
|
%strong= t('views.users.dossiers.merci.dossier_edit_l2')
|
||||||
|
= t('views.users.dossiers.merci.dossier_edit_l3')
|
||||||
|
%strong= t('views.users.dossiers.merci.dossier_edit_l4')
|
||||||
|
- if procedure.active_dossier_submitted_message
|
||||||
|
%p.m-2= procedure.active_dossier_submitted_message.message_on_submit_by_usager
|
||||||
|
|
||||||
|
.flex.column.align-center
|
||||||
|
= link_to t('views.users.dossiers.merci.acces_dossier'), dossier ? dossier_path(dossier) : "#dossier" , class: 'button large primary mt-4'
|
||||||
|
= link_to t('views.users.dossiers.merci.submit_dossier'), procedure_lien(procedure), class: 'mt-4'
|
||||||
|
|
||||||
|
.monavis
|
||||||
|
!= procedure.monavis_embed
|
|
@ -3,26 +3,4 @@
|
||||||
- content_for :footer do
|
- content_for :footer do
|
||||||
= render partial: "users/procedure_footer", locals: { procedure: @dossier.procedure, dossier: @dossier }
|
= render partial: "users/procedure_footer", locals: { procedure: @dossier.procedure, dossier: @dossier }
|
||||||
|
|
||||||
.merci
|
= render partial: 'users/dossiers/merci', locals: { dossier: @dossier, procedure: @dossier.procedure}
|
||||||
.container
|
|
||||||
= image_tag('user/envoi-dossier.svg', alt: '')
|
|
||||||
%h1= t('views.users.dossiers.merci.thanks')
|
|
||||||
%p.send
|
|
||||||
= t('views.users.dossiers.merci.dossier_send_l1')
|
|
||||||
%b= @dossier.procedure.libelle
|
|
||||||
= t('views.users.dossiers.merci.dossier_send_l2')
|
|
||||||
%p
|
|
||||||
= t('views.users.dossiers.merci.dossier_acces_l1')
|
|
||||||
%b= t('views.users.dossiers.merci.dossier_acces_l2')
|
|
||||||
%p
|
|
||||||
= t('views.users.dossiers.merci.dossier_edit_l1')
|
|
||||||
- if !@dossier.read_only?
|
|
||||||
%b= t('views.users.dossiers.merci.dossier_edit_l2')
|
|
||||||
= t('views.users.dossiers.merci.dossier_edit_l3')
|
|
||||||
%b= t('views.users.dossiers.merci.dossier_edit_l4')
|
|
||||||
|
|
||||||
.flex.column.align-center
|
|
||||||
= link_to t('views.users.dossiers.merci.acces_dossier'), dossier_path(@dossier), class: 'button large primary'
|
|
||||||
= link_to t('views.users.dossiers.merci.submit_dossier'), procedure_lien(@dossier.procedure)
|
|
||||||
.monavis
|
|
||||||
!= @dossier.procedure.monavis_embed
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
= content_for(:page_id, 'auth')
|
= content_for(:page_id, 'auth')
|
||||||
|
|
||||||
.auth-form.sign-in-form
|
#session-new.auth-form.sign-in-form
|
||||||
|
|
||||||
= form_for resource, url: user_session_path, html: { class: "form" } do |f|
|
= form_for resource, url: user_session_path, html: { class: "form" } do |f|
|
||||||
%h1.huge-title= t('views.users.sessions.new.sign_in')
|
%h1.huge-title= t('views.users.sessions.new.sign_in')
|
||||||
|
@ -23,15 +23,10 @@
|
||||||
|
|
||||||
= f.submit t('views.users.sessions.new.connection'), class: "button large primary expand"
|
= f.submit t('views.users.sessions.new.connection'), class: "button large primary expand"
|
||||||
|
|
||||||
.france-connect-login-separator
|
|
||||||
= t('views.shared.france_connect_login.separator')
|
|
||||||
- if AgentConnectService.enabled?
|
- if AgentConnectService.enabled?
|
||||||
|
.france-connect-login-separator
|
||||||
|
= t('views.shared.france_connect_login.separator')
|
||||||
.center
|
.center
|
||||||
%p.mb-2= t('views.users.sessions.new.instructor_or_admin')
|
%h2.important-header= t('views.users.sessions.new.state_civil_servant')
|
||||||
= link_to t('views.users.sessions.new.connect_with_agent_connect'), agent_connect_path
|
%br
|
||||||
%hr
|
= link_to t('views.users.sessions.new.connect_with_agent_connect'), agent_connect_path, class: "button expend secondary"
|
||||||
%p.center
|
|
||||||
%span= t('views.users.sessions.new.are_you_new', app_name: APPLICATION_NAME.gsub("-","‑")).html_safe
|
|
||||||
%br
|
|
||||||
%br
|
|
||||||
= link_to t('views.users.sessions.new.find_procedure'), COMMENT_TROUVER_MA_DEMARCHE_URL, target: "_blank", class: "button expend secondary"
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ FileUtils.chdir APP_ROOT do
|
||||||
system('bundle check') || system!('bundle install')
|
system('bundle check') || system!('bundle install')
|
||||||
|
|
||||||
# Install JavaScript dependencies
|
# Install JavaScript dependencies
|
||||||
|
system! 'node --version'
|
||||||
system! 'bin/yarn install'
|
system! 'bin/yarn install'
|
||||||
|
|
||||||
puts "\n== Updating webdrivers =="
|
puts "\n== Updating webdrivers =="
|
||||||
|
|
|
@ -15,7 +15,9 @@ FileUtils.chdir APP_ROOT do
|
||||||
puts '== Installing dependencies =='
|
puts '== Installing dependencies =='
|
||||||
system! 'gem install bundler --conservative'
|
system! 'gem install bundler --conservative'
|
||||||
system('bundle check') || system!('bundle install')
|
system('bundle check') || system!('bundle install')
|
||||||
|
system! 'node --version'
|
||||||
system! 'bin/yarn install'
|
system! 'bin/yarn install'
|
||||||
|
system! 'bin/yarn clean'
|
||||||
|
|
||||||
puts "\n== Updating webdrivers =="
|
puts "\n== Updating webdrivers =="
|
||||||
system! 'RAILS_ENV=test bin/rails webdrivers:chromedriver:update'
|
system! 'RAILS_ENV=test bin/rails webdrivers:chromedriver:update'
|
||||||
|
|
|
@ -1,5 +1,46 @@
|
||||||
{
|
{
|
||||||
"ignored_warnings": [
|
"ignored_warnings": [
|
||||||
|
{
|
||||||
|
"warning_type": "Cross-Site Scripting",
|
||||||
|
"warning_code": 2,
|
||||||
|
"fingerprint": "1b805585567775589825c0eda58cb84c074fc760d0a7afb101c023a51427f2b5",
|
||||||
|
"check_name": "CrossSiteScripting",
|
||||||
|
"message": "Unescaped model attribute",
|
||||||
|
"file": "app/views/users/dossiers/_merci.html.haml",
|
||||||
|
"line": 26,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
|
||||||
|
"code": "current_user.dossiers.includes(:procedure).find(params[:id]).procedure.monavis_embed",
|
||||||
|
"render_path": [
|
||||||
|
{
|
||||||
|
"type": "controller",
|
||||||
|
"class": "Users::DossiersController",
|
||||||
|
"method": "merci",
|
||||||
|
"line": 196,
|
||||||
|
"file": "app/controllers/users/dossiers_controller.rb",
|
||||||
|
"rendered": {
|
||||||
|
"name": "users/dossiers/merci",
|
||||||
|
"file": "app/views/users/dossiers/merci.html.haml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "template",
|
||||||
|
"name": "users/dossiers/merci",
|
||||||
|
"line": 6,
|
||||||
|
"file": "app/views/users/dossiers/merci.html.haml",
|
||||||
|
"rendered": {
|
||||||
|
"name": "users/dossiers/_merci",
|
||||||
|
"file": "app/views/users/dossiers/_merci.html.haml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"location": {
|
||||||
|
"type": "template",
|
||||||
|
"template": "users/dossiers/_merci"
|
||||||
|
},
|
||||||
|
"user_input": "current_user.dossiers.includes(:procedure)",
|
||||||
|
"confidence": "Weak",
|
||||||
|
"note": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"warning_type": "Cross-Site Scripting",
|
"warning_type": "Cross-Site Scripting",
|
||||||
"warning_code": 2,
|
"warning_code": 2,
|
||||||
|
@ -38,7 +79,7 @@
|
||||||
"check_name": "SQL",
|
"check_name": "SQL",
|
||||||
"message": "Possible SQL injection",
|
"message": "Possible SQL injection",
|
||||||
"file": "app/models/traitement.rb",
|
"file": "app/models/traitement.rb",
|
||||||
"line": 51,
|
"line": 52,
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||||
"code": "ActiveRecord::Base.connection.execute(\"select date_trunc('month', r1.processed_at::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL) as month, count(r1.processed_at)\\nfrom (#{Traitement.select(\"max(traitements.processed_at) as processed_at\").termine.where(:dossier => Dossier.state_termine.where(:groupe_instructeur => groupe_instructeurs)).group(:dossier_id).to_sql}) as r1\\ngroup by date_trunc('month', r1.processed_at::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL)\\norder by month desc\\n\")",
|
"code": "ActiveRecord::Base.connection.execute(\"select date_trunc('month', r1.processed_at::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL) as month, count(r1.processed_at)\\nfrom (#{Traitement.select(\"max(traitements.processed_at) as processed_at\").termine.where(:dossier => Dossier.state_termine.where(:groupe_instructeur => groupe_instructeurs)).group(:dossier_id).to_sql}) as r1\\ngroup by date_trunc('month', r1.processed_at::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL)\\norder by month desc\\n\")",
|
||||||
"render_path": null,
|
"render_path": null,
|
||||||
|
@ -51,37 +92,6 @@
|
||||||
"confidence": "Medium",
|
"confidence": "Medium",
|
||||||
"note": ""
|
"note": ""
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"warning_type": "Cross-Site Scripting",
|
|
||||||
"warning_code": 2,
|
|
||||||
"fingerprint": "483ae8c038244eb3ed709e89846335e2c8ff6579260348ec31d3d03d1c94ad64",
|
|
||||||
"check_name": "CrossSiteScripting",
|
|
||||||
"message": "Unescaped model attribute",
|
|
||||||
"file": "app/views/users/dossiers/merci.html.haml",
|
|
||||||
"line": 28,
|
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
|
|
||||||
"code": "current_user.dossiers.includes(:procedure).find(params[:id]).procedure.monavis_embed",
|
|
||||||
"render_path": [
|
|
||||||
{
|
|
||||||
"type": "controller",
|
|
||||||
"class": "Users::DossiersController",
|
|
||||||
"method": "merci",
|
|
||||||
"line": 195,
|
|
||||||
"file": "app/controllers/users/dossiers_controller.rb",
|
|
||||||
"rendered": {
|
|
||||||
"name": "users/dossiers/merci",
|
|
||||||
"file": "app/views/users/dossiers/merci.html.haml"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"location": {
|
|
||||||
"type": "template",
|
|
||||||
"template": "users/dossiers/merci"
|
|
||||||
},
|
|
||||||
"user_input": "current_user.dossiers.includes(:procedure)",
|
|
||||||
"confidence": "Weak",
|
|
||||||
"note": ""
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"warning_type": "SQL Injection",
|
"warning_type": "SQL Injection",
|
||||||
"warning_code": 0,
|
"warning_code": 0,
|
||||||
|
@ -102,26 +112,6 @@
|
||||||
"confidence": "Medium",
|
"confidence": "Medium",
|
||||||
"note": "The table and column are escaped, which should make this safe"
|
"note": "The table and column are escaped, which should make this safe"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"warning_type": "SQL Injection",
|
|
||||||
"warning_code": 0,
|
|
||||||
"fingerprint": "c0f93612a68c32da58f327e0b5fa33dd42fd8beb2984cf023338c5aadbbdacca",
|
|
||||||
"check_name": "SQL",
|
|
||||||
"message": "Possible SQL injection",
|
|
||||||
"file": "app/models/stat.rb",
|
|
||||||
"line": 83,
|
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
|
||||||
"code": "association.where(date_attribute => ((3.months.ago.beginning_of_month..max_date))).group(\"DATE_TRUNC('month', #{date_attribute}::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL)\")",
|
|
||||||
"render_path": null,
|
|
||||||
"location": {
|
|
||||||
"type": "method",
|
|
||||||
"class": "Stat",
|
|
||||||
"method": "last_four_months_hash"
|
|
||||||
},
|
|
||||||
"user_input": "date_attribute",
|
|
||||||
"confidence": "Weak",
|
|
||||||
"note": ""
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"warning_type": "Redirect",
|
"warning_type": "Redirect",
|
||||||
"warning_code": 18,
|
"warning_code": 18,
|
||||||
|
@ -129,7 +119,7 @@
|
||||||
"check_name": "Redirect",
|
"check_name": "Redirect",
|
||||||
"message": "Possible unprotected redirect",
|
"message": "Possible unprotected redirect",
|
||||||
"file": "app/controllers/instructeurs/procedures_controller.rb",
|
"file": "app/controllers/instructeurs/procedures_controller.rb",
|
||||||
"line": 195,
|
"line": 202,
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
|
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
|
||||||
"code": "redirect_to(Export.find_or_create_export(params[:export_format], (params[:time_span_type] or \"everything\"), current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url)",
|
"code": "redirect_to(Export.find_or_create_export(params[:export_format], (params[:time_span_type] or \"everything\"), current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url)",
|
||||||
"render_path": null,
|
"render_path": null,
|
||||||
|
@ -141,28 +131,8 @@
|
||||||
"user_input": "Export.find_or_create_export(params[:export_format], (params[:time_span_type] or \"everything\"), current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url",
|
"user_input": "Export.find_or_create_export(params[:export_format], (params[:time_span_type] or \"everything\"), current_instructeur.groupe_instructeurs.where(:procedure => procedure)).file.service_url",
|
||||||
"confidence": "High",
|
"confidence": "High",
|
||||||
"note": ""
|
"note": ""
|
||||||
},
|
|
||||||
{
|
|
||||||
"warning_type": "SQL Injection",
|
|
||||||
"warning_code": 0,
|
|
||||||
"fingerprint": "f2bb9bc6a56e44ab36ee18152c657395841cff354baed0a302b8d18650551529",
|
|
||||||
"check_name": "SQL",
|
|
||||||
"message": "Possible SQL injection",
|
|
||||||
"file": "app/models/stat.rb",
|
|
||||||
"line": 97,
|
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
|
||||||
"code": "association.where(\"#{date_attribute} < ?\", max_date).group(\"DATE_TRUNC('month', #{date_attribute}::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL)\")",
|
|
||||||
"render_path": null,
|
|
||||||
"location": {
|
|
||||||
"type": "method",
|
|
||||||
"class": "Stat",
|
|
||||||
"method": "cumulative_hash"
|
|
||||||
},
|
|
||||||
"user_input": "date_attribute",
|
|
||||||
"confidence": "Weak",
|
|
||||||
"note": ""
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updated": "2021-12-01 17:39:08 -1000",
|
"updated": "2022-02-22 15:46:39 +0100",
|
||||||
"brakeman_version": "5.1.1"
|
"brakeman_version": "5.1.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,8 @@ Rails.application.configure do
|
||||||
protocol: :http
|
protocol: :http
|
||||||
}
|
}
|
||||||
|
|
||||||
# Use Content-Security-Policy-Report-Only headers
|
# Disallow all connections to external domains during tests
|
||||||
config.content_security_policy_report_only = true
|
config.content_security_policy_report_only = false
|
||||||
|
|
||||||
config.active_job.queue_adapter = :test
|
config.active_job.queue_adapter = :test
|
||||||
config.active_storage.service = :test
|
config.active_storage.service = :test
|
||||||
|
|
|
@ -5,22 +5,20 @@
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
||||||
|
|
||||||
Rails.application.config.content_security_policy do |policy|
|
Rails.application.config.content_security_policy do |policy|
|
||||||
# Whitelist image
|
|
||||||
images_whitelist = ["*.openstreetmap.org", "*.cloud.ovh.net", "*"]
|
images_whitelist = ["*.openstreetmap.org", "*.cloud.ovh.net", "*"]
|
||||||
images_whitelist << URI(DS_PROXY_URL).host if DS_PROXY_URL.present?
|
images_whitelist << URI(DS_PROXY_URL).host if DS_PROXY_URL.present?
|
||||||
images_whitelist << URI(MATOMO_IFRAME_URL).host if MATOMO_IFRAME_URL.present?
|
images_whitelist << URI(MATOMO_IFRAME_URL).host if MATOMO_IFRAME_URL.present?
|
||||||
policy.img_src(:self, :data, :blob, *images_whitelist)
|
policy.img_src(:self, :data, :blob, *images_whitelist)
|
||||||
|
|
||||||
# Whitelist JS: nous, sendinblue et matomo
|
# Javascript: allow us, SendInBlue and Matomo.
|
||||||
# miniprofiler et nous avons quelques boutons inline :(
|
# We need unsafe_inline because miniprofiler and us have some inline buttons :(
|
||||||
scripts_whitelist = ["*.sendinblue.com", "*.crisp.chat", "crisp.chat", "*.sibautomation.com", "sibautomation.com", "cdn.jsdelivr.net", "maxcdn.bootstrapcdn.com", "code.jquery.com"]
|
scripts_whitelist = ["*.sendinblue.com", "*.crisp.chat", "crisp.chat", "*.sibautomation.com", "sibautomation.com", "cdn.jsdelivr.net", "maxcdn.bootstrapcdn.com", "code.jquery.com"]
|
||||||
scripts_whitelist << URI(MATOMO_IFRAME_URL).host if MATOMO_IFRAME_URL.present?
|
scripts_whitelist << URI(MATOMO_IFRAME_URL).host if MATOMO_IFRAME_URL.present?
|
||||||
policy.script_src(:self, :unsafe_eval, :unsafe_inline, :blob, *scripts_whitelist)
|
policy.script_src(:self, :unsafe_eval, :unsafe_inline, :blob, *scripts_whitelist)
|
||||||
|
|
||||||
# Pour les CSS, on a beaucoup de style inline et quelques balises <style>
|
# CSS: We have a lot of inline style, and some <style> tags.
|
||||||
# c'est trop compliqué pour être rectifié immédiatement (et sans valeur ajoutée:
|
# It's too complicated to be fixed right now (and it wouldn't add value: this is hardcoded in views, so not subject to injections)
|
||||||
# c'est hardcodé dans les vues, donc pas injectable).
|
policy.style_src(:self, :unsafe_inline, "*.crisp.chat", "crisp.chat", 'cdn.jsdelivr.net', 'maxcdn.bootstrapcdn.com')
|
||||||
policy.style_src(:self, "*.crisp.chat", "crisp.chat", 'cdn.jsdelivr.net', 'maxcdn.bootstrapcdn.com', :unsafe_inline)
|
|
||||||
|
|
||||||
connect_whitelist = ["wss://*.crisp.chat", "*.crisp.chat", "in-automate.sendinblue.com", "app.franceconnect.gouv.fr", "sentry.io", "openmaptiles.geo.data.gouv.fr", "openmaptiles.github.io", "tiles.geo.api.gouv.fr", "wxs.ign.fr"]
|
connect_whitelist = ["wss://*.crisp.chat", "*.crisp.chat", "in-automate.sendinblue.com", "app.franceconnect.gouv.fr", "sentry.io", "openmaptiles.geo.data.gouv.fr", "openmaptiles.github.io", "tiles.geo.api.gouv.fr", "wxs.ign.fr"]
|
||||||
connect_whitelist << ENV.fetch('APP_HOST')
|
connect_whitelist << ENV.fetch('APP_HOST')
|
||||||
|
@ -31,22 +29,34 @@ Rails.application.config.content_security_policy do |policy|
|
||||||
connect_whitelist << Rails.application.secrets.matomo[:host] if Rails.application.secrets.matomo[:enabled]
|
connect_whitelist << Rails.application.secrets.matomo[:host] if Rails.application.secrets.matomo[:enabled]
|
||||||
policy.connect_src(:self, *connect_whitelist)
|
policy.connect_src(:self, *connect_whitelist)
|
||||||
|
|
||||||
|
# Frames: allow Matomo's iframe on the /suivi page
|
||||||
frame_whitelist = []
|
frame_whitelist = []
|
||||||
frame_whitelist << URI(MATOMO_IFRAME_URL).host if Rails.application.secrets.matomo[:enabled]
|
frame_whitelist << URI(MATOMO_IFRAME_URL).host if Rails.application.secrets.matomo[:enabled]
|
||||||
policy.frame_src(:self, *frame_whitelist)
|
policy.frame_src(:self, *frame_whitelist)
|
||||||
|
|
||||||
# Pour tout le reste, par défaut on accepte uniquement ce qui vient de chez nous
|
# Everything else: allow us
|
||||||
# et dans la notification on inclue la source de l'erreur
|
# Add the error source in the violation notification
|
||||||
default_whitelist = ["fonts.gstatic.com", "in-automate.sendinblue.com", "player.vimeo.com", "app.franceconnect.gouv.fr", "sentry.io", "*.crisp.chat", "crisp.chat", "*.crisp.help", "*.sibautomation.com", "sibautomation.com", "data"]
|
default_whitelist = ["fonts.gstatic.com", "in-automate.sendinblue.com", "player.vimeo.com", "app.franceconnect.gouv.fr", "sentry.io", "*.crisp.chat", "crisp.chat", "*.crisp.help", "*.sibautomation.com", "sibautomation.com", "data"]
|
||||||
default_whitelist << URI(DS_PROXY_URL).host if DS_PROXY_URL.present?
|
default_whitelist << URI(DS_PROXY_URL).host if DS_PROXY_URL.present?
|
||||||
policy.default_src(:self, :data, :blob, :report_sample, *default_whitelist)
|
policy.default_src(:self, :data, :blob, :report_sample, *default_whitelist)
|
||||||
|
|
||||||
if Rails.env.development?
|
if Rails.env.development?
|
||||||
# Les CSP ne sont pas appliquées en dev: on notifie cependant une url quelconque de la violation
|
# Allow LiveReload requests
|
||||||
# pour détecter les erreurs lors de l'ajout d'une nouvelle brique externe durant le développement
|
|
||||||
policy.report_uri "http://#{ENV.fetch('APP_HOST')}/csp/"
|
|
||||||
# En développement, quand bin/webpack-dev-server est utilisé, on autorise les requêtes faites par le live-reload
|
|
||||||
policy.connect_src(*policy.connect_src, "ws://localhost:3035", "http://localhost:3035")
|
policy.connect_src(*policy.connect_src, "ws://localhost:3035", "http://localhost:3035")
|
||||||
|
|
||||||
|
# CSP are not enforced in development (see content_security_policy_report_only in development.rb)
|
||||||
|
# However we notify a random local URL, to see breakage in the DevTools when adding a new external resource.
|
||||||
|
policy.report_uri "http://#{ENV.fetch('APP_HOST')}/csp/"
|
||||||
|
|
||||||
|
elsif Rails.env.test?
|
||||||
|
# Disallow all connections to external domains during tests
|
||||||
|
policy.img_src(:self, :data, :blob)
|
||||||
|
policy.script_src(:self, :unsafe_eval, :unsafe_inline, :blob)
|
||||||
|
policy.style_src(:self)
|
||||||
|
policy.connect_src(:self)
|
||||||
|
policy.frame_src(:self)
|
||||||
|
policy.default_src(:self, :data, :blob)
|
||||||
|
|
||||||
else
|
else
|
||||||
policy.report_uri CSP_REPORT_URI if CSP_REPORT_URI.present?
|
policy.report_uri CSP_REPORT_URI if CSP_REPORT_URI.present?
|
||||||
end
|
end
|
||||||
|
|
|
@ -56,6 +56,7 @@ en:
|
||||||
line1: A simple tool
|
line1: A simple tool
|
||||||
line2: to manage dematerialized
|
line2: to manage dematerialized
|
||||||
line3: administrative forms.
|
line3: administrative forms.
|
||||||
|
are_you_new: First time on %{app_name}?
|
||||||
locale_dropdown:
|
locale_dropdown:
|
||||||
languages: "Languages"
|
languages: "Languages"
|
||||||
notifications:
|
notifications:
|
||||||
|
@ -215,10 +216,9 @@ en:
|
||||||
remember_me: Remember me
|
remember_me: Remember me
|
||||||
reset_password: Forgot password?
|
reset_password: Forgot password?
|
||||||
connection: Sign in
|
connection: Sign in
|
||||||
are_you_new: First time on %{app_name}?
|
|
||||||
find_procedure: Find your procedure
|
find_procedure: Find your procedure
|
||||||
instructor_or_admin: Instructor or Administrator ?
|
state_civil_servant: Are you a state civil servant?
|
||||||
connect_with_agent_connect: Connect with AgentConnect
|
connect_with_agent_connect: Visit our dedicated page
|
||||||
passwords:
|
passwords:
|
||||||
reset_link_sent:
|
reset_link_sent:
|
||||||
got_it: Got it!
|
got_it: Got it!
|
||||||
|
|
|
@ -47,6 +47,7 @@ fr:
|
||||||
line1: Un outil simple
|
line1: Un outil simple
|
||||||
line2: pour gérer les formulaires
|
line2: pour gérer les formulaires
|
||||||
line3: administratifs dématérialisés.
|
line3: administratifs dématérialisés.
|
||||||
|
are_you_new: Vous êtes nouveau sur %{app_name} ?
|
||||||
locale_dropdown:
|
locale_dropdown:
|
||||||
languages: "Langues"
|
languages: "Langues"
|
||||||
notifications:
|
notifications:
|
||||||
|
@ -212,10 +213,9 @@ fr:
|
||||||
remember_me: Se souvenir de moi
|
remember_me: Se souvenir de moi
|
||||||
reset_password: Mot de passe oublié ?
|
reset_password: Mot de passe oublié ?
|
||||||
connection: Se connecter
|
connection: Se connecter
|
||||||
are_you_new: Vous êtes nouveau sur %{app_name} ?
|
|
||||||
find_procedure: Trouvez votre démarche
|
find_procedure: Trouvez votre démarche
|
||||||
instructor_or_admin: Vous êtes instructeur ou administrateur ?
|
state_civil_servant: Vous êtes agent de la fonction publique d’État ?
|
||||||
connect_with_agent_connect: Se connecter avec AgentConnect
|
connect_with_agent_connect: Accédez à notre page dédiée
|
||||||
passwords:
|
passwords:
|
||||||
reset_link_sent:
|
reset_link_sent:
|
||||||
email_sent_html: "Nous vous avons envoyé un email à l’adresse <strong>%{email}</strong>."
|
email_sent_html: "Nous vous avons envoyé un email à l’adresse <strong>%{email}</strong>."
|
||||||
|
|
|
@ -2,10 +2,21 @@ en:
|
||||||
agent_connect:
|
agent_connect:
|
||||||
agent:
|
agent:
|
||||||
index:
|
index:
|
||||||
connect: Connect with AgentConnect
|
|
||||||
intro_html: |
|
|
||||||
AgentConnect allows <b class='bold'>instructors et administrators</b> to use their usual login credentials to connect to %{app_name}.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
Only agents of <b class='bold'>the Ministry of Ecological Transition</b> can currently benefit from it.
|
|
||||||
cta: Connect with AgentConnect
|
cta: Connect with AgentConnect
|
||||||
|
you_are_an_agent: Are you an employee of the state civil service or of a state operator?
|
||||||
|
in_progress_html: |
|
||||||
|
<p>
|
||||||
|
<b class="bold">AgentConnect is currently being deployed.</b>
|
||||||
|
<br>
|
||||||
|
The ministries and operators that can currently benefit from it are :
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>the Ministry of Ecological Transition</li>
|
||||||
|
</ul>
|
||||||
|
you_are_a_citizen: You are an individual ?
|
||||||
|
citizen_page: Go to our dedicated page
|
||||||
|
connect_html: |
|
||||||
|
<h1 class="mt-2 mb-2">Connect</h1>
|
||||||
|
<p><b class="bold">With AgentConnect</b></p>
|
||||||
|
whats_agentconnect: 'What is AgentConnect?'
|
||||||
|
pro_email: Professional email (nom@site.com)
|
||||||
|
|
|
@ -2,10 +2,21 @@ fr:
|
||||||
agent_connect:
|
agent_connect:
|
||||||
agent:
|
agent:
|
||||||
index:
|
index:
|
||||||
connect: Connectez-vous avec AgentConnect
|
|
||||||
intro_html: |
|
|
||||||
AgentConnect permet aux <b class='bold'>instructeurs et administrateurs</b> d’utiliser leurs identifiants habituels pour se connecter à %{app_name}.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
Seul les agents du <b class='bold'>ministère de la Transition écologique</b> peuvent actuellement en bénéficier.
|
|
||||||
cta: S’identifier avec AgentConnect
|
cta: S’identifier avec AgentConnect
|
||||||
|
you_are_an_agent: Vous êtes agent de la fonction publique dʼÉtat ou dʼun opérateur de lʼÉtat ?
|
||||||
|
in_progress_html: |
|
||||||
|
<p>
|
||||||
|
<b class="bold">AgentConnect est en cours de déploiement.</b>
|
||||||
|
<br>
|
||||||
|
Les ministères et opérateurs qui peuvent l'utiliser à ce jour sont :
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>le ministère de la Transition écologique</li>
|
||||||
|
</ul>
|
||||||
|
you_are_a_citizen: Vous êtes un particulier ?
|
||||||
|
citizen_page: Accéder à notre page dédiée
|
||||||
|
connect_html: |
|
||||||
|
<h1 class="mt-2 mb-2">Connectez-vous</h1>
|
||||||
|
<p><b class="bold">Avec AgentConnect</b></p>
|
||||||
|
whats_agentconnect: 'Quʼest ce quʼAgentConnect ?'
|
||||||
|
pro_email: Email professionnel (nom@site.com)
|
||||||
|
|
|
@ -8,6 +8,7 @@ en:
|
||||||
To read the message and answer it, select the following link:
|
To read the message and answer it, select the following link:
|
||||||
body_draft_html: |
|
body_draft_html: |
|
||||||
You received <b>a new message</b> from the service in charge of reviewing the file you started a draft for on the procedure « %{libelle_demarche} ».
|
You received <b>a new message</b> from the service in charge of reviewing the file you started a draft for on the procedure « %{libelle_demarche} ».
|
||||||
contact: If you chose to contact the service, please use the email available below in the page.
|
contact_html: "If you chose to contact the service, please send an email directly to this address: <a href=\"mailto:%{email}\">%{email}</a>"
|
||||||
|
contact_no_email: If you chose to contact the service, please use the contact infos available below.
|
||||||
access_message: Read the message
|
access_message: Read the message
|
||||||
access_file: Open file
|
access_file: Open file
|
||||||
|
|
|
@ -3,11 +3,12 @@ fr:
|
||||||
notify_new_answer:
|
notify_new_answer:
|
||||||
subject: Nouveau message pour votre dossier nº %{dossier_id} « %{libelle_demarche} »
|
subject: Nouveau message pour votre dossier nº %{dossier_id} « %{libelle_demarche} »
|
||||||
body_html: |
|
body_html: |
|
||||||
Vous avez reçu un <b>nouveau message</b> de la part du service en charge de votre dossier sur la démarche « %{libelle_demarche} ».
|
Vous avez reçu un <b>nouveau message</b> de la part de l’administration en charge de votre dossier sur la démarche « %{libelle_demarche} ».
|
||||||
link: |
|
link: |
|
||||||
Pour consulter le message et y répondre, cliquez sur le bouton ci-dessous :
|
Pour consulter le message et y répondre, cliquez sur le bouton ci-dessous :
|
||||||
body_draft_html: |
|
body_draft_html: |
|
||||||
Vous avez reçu un <b>nouveau message</b>du service pour lequel votre dossier est en brouillon pour la démarche « %{libelle_demarche} ».
|
Vous avez reçu un <b>nouveau message</b> de l’administration, au sujet de votre dossier en brouillon pour la démarche « %{libelle_demarche} ».
|
||||||
contact: Si vous souhaitez contacter le service, merci de le faire directement à l'aide de l'email en bas de page.
|
contact_html: "Si vous souhaitez répondre à ce message, contactez directement l’administration à l’adresse suivante : <a href=\"mailto:%{email}\">%{email}</a>"
|
||||||
|
contact_no_email: Si vous souhaitez répondre à ce message, contactez directement l’administration à l’aide des coordonnées en bas de cet email.
|
||||||
access_message: Lire le message
|
access_message: Lire le message
|
||||||
access_file: Voir le dossier
|
access_file: Voir le dossier
|
||||||
|
|
|
@ -466,6 +466,7 @@ Rails.application.routes.draw do
|
||||||
resource :attestation_template, only: [:edit, :update, :create] do
|
resource :attestation_template, only: [:edit, :update, :create] do
|
||||||
get 'preview', on: :member
|
get 'preview', on: :member
|
||||||
end
|
end
|
||||||
|
resource :dossier_submitted_message, only: [:edit, :update, :create]
|
||||||
# ADDED TO ACCESS IT FROM THE IFRAME
|
# ADDED TO ACCESS IT FROM THE IFRAME
|
||||||
get 'attestation_template/preview' => 'attestation_templates#preview'
|
get 'attestation_template/preview' => 'attestation_templates#preview'
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
class CreateDossierSubmittedMessages < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
create_table :dossier_submitted_messages do |t|
|
||||||
|
t.string :message_on_submit_by_usager
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
add_reference :procedure_revisions, :dossier_submitted_message, foreign_key: { to_table: :dossier_submitted_messages }, null: true, index: true
|
||||||
|
end
|
||||||
|
end
|
13
db/schema.rb
13
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2022_02_04_093401) do
|
ActiveRecord::Schema.define(version: 2022_02_04_130722) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -275,6 +275,12 @@ ActiveRecord::Schema.define(version: 2022_02_04_093401) do
|
||||||
t.index ["keep_until"], name: "index_dossier_operation_logs_on_keep_until"
|
t.index ["keep_until"], name: "index_dossier_operation_logs_on_keep_until"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "dossier_submitted_messages", force: :cascade do |t|
|
||||||
|
t.string "message_on_submit_by_usager"
|
||||||
|
t.datetime "created_at", precision: 6, null: false
|
||||||
|
t.datetime "updated_at", precision: 6, null: false
|
||||||
|
end
|
||||||
|
|
||||||
create_table "dossier_transfer_logs", force: :cascade do |t|
|
create_table "dossier_transfer_logs", force: :cascade do |t|
|
||||||
t.string "from", null: false
|
t.string "from", null: false
|
||||||
t.string "to", null: false
|
t.string "to", null: false
|
||||||
|
@ -324,10 +330,10 @@ ActiveRecord::Schema.define(version: 2022_02_04_093401) do
|
||||||
t.datetime "identity_updated_at"
|
t.datetime "identity_updated_at"
|
||||||
t.datetime "depose_at"
|
t.datetime "depose_at"
|
||||||
t.datetime "hidden_by_user_at"
|
t.datetime "hidden_by_user_at"
|
||||||
|
t.datetime "hidden_by_administration_at"
|
||||||
t.string "hidden_by_reason"
|
t.string "hidden_by_reason"
|
||||||
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
|
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
|
||||||
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
|
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
|
||||||
t.datetime "hidden_by_administration_at"
|
|
||||||
t.index ["archived"], name: "index_dossiers_on_archived"
|
t.index ["archived"], name: "index_dossiers_on_archived"
|
||||||
t.index ["dossier_transfer_id"], name: "index_dossiers_on_dossier_transfer_id"
|
t.index ["dossier_transfer_id"], name: "index_dossiers_on_dossier_transfer_id"
|
||||||
t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id"
|
t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id"
|
||||||
|
@ -595,7 +601,9 @@ ActiveRecord::Schema.define(version: 2022_02_04_093401) do
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.datetime "published_at"
|
t.datetime "published_at"
|
||||||
t.bigint "attestation_template_id"
|
t.bigint "attestation_template_id"
|
||||||
|
t.bigint "dossier_submitted_message_id"
|
||||||
t.index ["attestation_template_id"], name: "index_procedure_revisions_on_attestation_template_id"
|
t.index ["attestation_template_id"], name: "index_procedure_revisions_on_attestation_template_id"
|
||||||
|
t.index ["dossier_submitted_message_id"], name: "index_procedure_revisions_on_dossier_submitted_message_id"
|
||||||
t.index ["procedure_id"], name: "index_procedure_revisions_on_procedure_id"
|
t.index ["procedure_id"], name: "index_procedure_revisions_on_procedure_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -876,6 +884,7 @@ ActiveRecord::Schema.define(version: 2022_02_04_093401) do
|
||||||
add_foreign_key "procedure_revision_types_de_champ", "procedure_revisions", column: "revision_id"
|
add_foreign_key "procedure_revision_types_de_champ", "procedure_revisions", column: "revision_id"
|
||||||
add_foreign_key "procedure_revision_types_de_champ", "types_de_champ"
|
add_foreign_key "procedure_revision_types_de_champ", "types_de_champ"
|
||||||
add_foreign_key "procedure_revisions", "attestation_templates"
|
add_foreign_key "procedure_revisions", "attestation_templates"
|
||||||
|
add_foreign_key "procedure_revisions", "dossier_submitted_messages"
|
||||||
add_foreign_key "procedure_revisions", "procedures"
|
add_foreign_key "procedure_revisions", "procedures"
|
||||||
add_foreign_key "procedures", "procedure_revisions", column: "draft_revision_id"
|
add_foreign_key "procedures", "procedure_revisions", column: "draft_revision_id"
|
||||||
add_foreign_key "procedures", "procedure_revisions", column: "published_revision_id"
|
add_foreign_key "procedures", "procedure_revisions", column: "published_revision_id"
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: cleanup_deleted_dossiers'
|
||||||
|
task cleanup_deleted_dossiers: :environment do
|
||||||
|
puts "Running deploy task 'cleanup_deleted_dossiers'"
|
||||||
|
|
||||||
|
DeletedDossier.where(state: :brouillon).destroy_all
|
||||||
|
|
||||||
|
AfterParty::TaskRecord.create version: '20200326133630'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,27 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: process_expired_dossiers_en_construction'
|
||||||
|
task process_expired_dossiers_en_construction: :environment do
|
||||||
|
puts "Running deploy task 'process_expired_dossiers_en_construction'"
|
||||||
|
|
||||||
|
if ENV['APP_NAME'] == 'tps'
|
||||||
|
dossiers_close_to_expiration = Dossier
|
||||||
|
.en_construction_close_to_expiration
|
||||||
|
.without_en_construction_expiration_notice_sent
|
||||||
|
|
||||||
|
ExpiredDossiersDeletionService.send_expiration_notices(dossiers_close_to_expiration)
|
||||||
|
|
||||||
|
BATCH_SIZE = 1000
|
||||||
|
|
||||||
|
((dossiers_close_to_expiration.count / BATCH_SIZE).ceil + 1).times do |n|
|
||||||
|
dossiers_close_to_expiration
|
||||||
|
.offset(n * BATCH_SIZE)
|
||||||
|
.limit(BATCH_SIZE)
|
||||||
|
.update_all(en_construction_close_to_expiration_notice_sent_at: Time.zone.now + n.days)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord.create version: '20200401123317'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,35 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: fix_champ_etablissement'
|
||||||
|
task fix_champ_etablissement: :environment do
|
||||||
|
puts "Running deploy task 'fix_champ_etablissement'"
|
||||||
|
|
||||||
|
etablissements = Etablissement.joins(:champ).where.not(dossier_id: nil).where('etablissements.created_at > ?', 1.month.ago)
|
||||||
|
dossiers_modif = []
|
||||||
|
etablissements.find_each do |e|
|
||||||
|
if e.dossier
|
||||||
|
user = e.dossier.user
|
||||||
|
dossier = e.dossier
|
||||||
|
if user.dossiers.count == 1 && user.siret == e.champ.value
|
||||||
|
e.update!(dossier_id: nil)
|
||||||
|
dossier.reload.etablissement = e.reload.dup
|
||||||
|
dossier.save!
|
||||||
|
dossiers_modif << dossier.id
|
||||||
|
fetch_api_entreprise_infos(dossier.etablissement.id, dossier.procedure.id, user.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
puts "Nb dossiers modifiés: #{dossiers_modif.size}"
|
||||||
|
AfterParty::TaskRecord.create version: '20200527124112'
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_api_entreprise_infos(etablissement_id, procedure_id, user_id)
|
||||||
|
[
|
||||||
|
APIEntreprise::EntrepriseJob, APIEntreprise::AssociationJob, APIEntreprise::ExercicesJob,
|
||||||
|
APIEntreprise::EffectifsJob, APIEntreprise::EffectifsAnnuelsJob, APIEntreprise::AttestationSocialeJob,
|
||||||
|
APIEntreprise::BilansBdfJob
|
||||||
|
].each do |job|
|
||||||
|
job.perform_later(etablissement_id, procedure_id)
|
||||||
|
end
|
||||||
|
APIEntreprise::AttestationFiscaleJob.perform_later(etablissement_id, procedure_id, user_id)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,20 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: fix_dossier_etablissement'
|
||||||
|
task fix_dossier_etablissement: :environment do
|
||||||
|
puts "Running deploy task 'fix_dossier_etablissement'"
|
||||||
|
|
||||||
|
etablissements = Etablissement.joins(:champ).where.not(dossier_id: nil).where('etablissements.created_at > ?', 1.month.ago)
|
||||||
|
dossiers_modif = []
|
||||||
|
etablissements.find_each do |e|
|
||||||
|
if e.dossier
|
||||||
|
dossier = e.dossier
|
||||||
|
e.update!(dossier_id: nil)
|
||||||
|
dossier.reload.etablissement = e.reload.dup
|
||||||
|
dossier.save!
|
||||||
|
dossiers_modif << dossier.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
puts "Nb dossiers modifiés: #{dossiers_modif.size}"
|
||||||
|
AfterParty::TaskRecord.create version: '20200528124044'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,25 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: drop_down_list_options_to_json'
|
||||||
|
task drop_down_list_options_to_json: :environment do
|
||||||
|
puts "Running deploy task 'drop_down_list_options_to_json'"
|
||||||
|
|
||||||
|
types_de_champ = TypeDeChamp.joins(:drop_down_list).where(type_champ: [
|
||||||
|
TypeDeChamp.type_champs.fetch(:drop_down_list),
|
||||||
|
TypeDeChamp.type_champs.fetch(:multiple_drop_down_list),
|
||||||
|
TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
|
||||||
|
])
|
||||||
|
progress = ProgressReport.new(types_de_champ.count)
|
||||||
|
types_de_champ.find_each do |type_de_champ|
|
||||||
|
type_de_champ.drop_down_list_value = type_de_champ.drop_down_list_value
|
||||||
|
if type_de_champ.save
|
||||||
|
type_de_champ.drop_down_list.destroy
|
||||||
|
end
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord.create version: '20200618121241'
|
||||||
|
end
|
||||||
|
end
|
22
lib/tasks/deployment/20200625113026_migrate_revisions.rake
Normal file
22
lib/tasks/deployment/20200625113026_migrate_revisions.rake
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: migrate_revisions'
|
||||||
|
task migrate_revisions: :environment do
|
||||||
|
puts "Running deploy task 'migrate_revisions'"
|
||||||
|
|
||||||
|
procedures = Procedure.with_discarded.where(draft_revision_id: nil)
|
||||||
|
progress = ProgressReport.new(procedures.count)
|
||||||
|
|
||||||
|
puts "Processing procedures"
|
||||||
|
procedures.find_each do |procedure|
|
||||||
|
RevisionsMigration.add_revisions(procedure)
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
TmpDossiersMigrateRevisionsJob.perform_later([])
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord.create version: '20200625113026'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,18 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: add_traitements_from_dossiers'
|
||||||
|
task add_traitements_from_dossiers: :environment do
|
||||||
|
puts "Running deploy task 'add_traitements_from_dossiers'"
|
||||||
|
|
||||||
|
dossiers_termines = Dossier.state_termine
|
||||||
|
progress = ProgressReport.new(dossiers_termines.count)
|
||||||
|
dossiers_termines.find_each do |dossier|
|
||||||
|
dossier.traitements.create!(state: dossier.state, motivation: dossier.motivation, processed_at: dossier.processed_at)
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord.create version: '20200630154829'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,18 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: add_default_skip_validation_to_piece_justificative'
|
||||||
|
task add_default_skip_validation_to_piece_justificative: :environment do
|
||||||
|
puts "Running deploy task 'add_default_skip_validation_to_piece_justificative'"
|
||||||
|
|
||||||
|
tdcs = TypeDeChamp.where(type_champ: TypeDeChamp.type_champs.fetch(:piece_justificative))
|
||||||
|
progress = ProgressReport.new(tdcs.count)
|
||||||
|
tdcs.find_each do |tdc|
|
||||||
|
tdc.update(skip_pj_validation: true)
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord.create version: '20200708101123'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,25 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: fix_cloned_revisions'
|
||||||
|
task fix_cloned_revisions: :environment do
|
||||||
|
puts "Running deploy task 'fix_cloned_revisions'"
|
||||||
|
|
||||||
|
Procedure.with_discarded.where(aasm_state: :brouillon).where.not(published_revision_id: nil).update_all(published_revision_id: nil)
|
||||||
|
|
||||||
|
types_de_champ = TypeDeChamp.joins(:revision).where('types_de_champ.procedure_id != procedure_revisions.procedure_id')
|
||||||
|
progress = ProgressReport.new(types_de_champ.count)
|
||||||
|
|
||||||
|
types_de_champ.find_each do |type_de_champ|
|
||||||
|
procedure = type_de_champ.procedure ? type_de_champ.procedure : Procedure.with_discarded.find(type_de_champ.procedure_id)
|
||||||
|
revision_id = procedure.published_revision_id || procedure.draft_revision_id
|
||||||
|
type_de_champ.update_column(:revision_id, revision_id)
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord
|
||||||
|
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,71 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: fix_geo_areas_geometry'
|
||||||
|
task fix_geo_areas_geometry: :environment do
|
||||||
|
puts "Running deploy task 'fix_geo_areas_geometry'"
|
||||||
|
|
||||||
|
geometry_collections = GeoArea.where("geometry -> 'type' = '\"GeometryCollection\"'")
|
||||||
|
multi_polygons = GeoArea.where("geometry -> 'type' = '\"MultiPolygon\"'")
|
||||||
|
multi_line_strings = GeoArea.where("geometry -> 'type' = '\"MultiLineString\"'")
|
||||||
|
|
||||||
|
def valid_geometry?(geometry)
|
||||||
|
RGeo::GeoJSON.decode(geometry.to_json, geo_factory: RGeo::Geographic.simple_mercator_factory)
|
||||||
|
true
|
||||||
|
rescue
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
progress = ProgressReport.new(geometry_collections.count)
|
||||||
|
geometry_collections.find_each do |geometry_collection|
|
||||||
|
geometry_collection.geometry['geometries'].each do |geometry|
|
||||||
|
if valid_geometry?(geometry)
|
||||||
|
geometry_collection.champ.geo_areas.create!(geometry: geometry, source: 'selection_utilisateur')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
geometry_collection.destroy
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
progress = ProgressReport.new(multi_line_strings.count)
|
||||||
|
multi_line_strings.find_each do |multi_line_string|
|
||||||
|
multi_line_string.geometry['coordinates'].each do |coordinates|
|
||||||
|
geometry = {
|
||||||
|
type: 'LineString',
|
||||||
|
coordinates: coordinates
|
||||||
|
}
|
||||||
|
|
||||||
|
if valid_geometry?(geometry)
|
||||||
|
multi_line_string.champ.geo_areas.create!(geometry: geometry, source: 'selection_utilisateur')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
multi_line_string.destroy
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
progress = ProgressReport.new(multi_polygons.count)
|
||||||
|
multi_polygons.find_each do |multi_polygon|
|
||||||
|
multi_polygon.geometry['coordinates'].each do |coordinates|
|
||||||
|
geometry = {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: coordinates
|
||||||
|
}
|
||||||
|
|
||||||
|
if valid_geometry?(geometry)
|
||||||
|
multi_polygon.champ.geo_areas.create!(geometry: geometry, source: 'selection_utilisateur')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
multi_polygon.destroy
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord
|
||||||
|
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,50 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: migrate_filters_to_use_stable_id'
|
||||||
|
task migrate_filters_to_use_stable_id: :environment do
|
||||||
|
puts "Running deploy task 'migrate_filters_to_use_stable_id'"
|
||||||
|
|
||||||
|
procedure_presentations = ProcedurePresentation.where("filters -> 'migrated' IS NULL")
|
||||||
|
progress = ProgressReport.new(procedure_presentations.count)
|
||||||
|
procedure_presentations.find_each do |procedure_presentation|
|
||||||
|
filters = procedure_presentation.filters
|
||||||
|
sort = procedure_presentation.sort
|
||||||
|
displayed_fields = procedure_presentation.displayed_fields
|
||||||
|
|
||||||
|
['tous', 'suivis', 'traites', 'a-suivre', 'archives'].each do |statut|
|
||||||
|
filters[statut] = filters[statut].map do |filter|
|
||||||
|
table, column = filter.values_at('table', 'column')
|
||||||
|
if table && (table == 'type_de_champ' || table == 'type_de_champ_private')
|
||||||
|
type_de_champ = TypeDeChamp.find_by(id: column)
|
||||||
|
filter['column'] = type_de_champ&.stable_id&.to_s
|
||||||
|
end
|
||||||
|
filter
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table, column = sort.values_at('table', 'column')
|
||||||
|
if table && (table == 'type_de_champ' || table == 'type_de_champ_private')
|
||||||
|
type_de_champ = TypeDeChamp.find_by(id: column)
|
||||||
|
sort['column'] = type_de_champ&.stable_id&.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
displayed_fields = displayed_fields.map do |displayed_field|
|
||||||
|
table, column = displayed_field.values_at('table', 'column')
|
||||||
|
if table && (table == 'type_de_champ' || table == 'type_de_champ_private')
|
||||||
|
type_de_champ = TypeDeChamp.find_by(id: column)
|
||||||
|
displayed_field['column'] = type_de_champ&.stable_id&.to_s
|
||||||
|
end
|
||||||
|
displayed_field
|
||||||
|
end
|
||||||
|
|
||||||
|
filters['migrated'] = true
|
||||||
|
procedure_presentation.update_columns(filters: filters, sort: sort, displayed_fields: displayed_fields)
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord
|
||||||
|
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
11
lib/tasks/deployment/20201006123842_setup_first_stats.rake
Normal file
11
lib/tasks/deployment/20201006123842_setup_first_stats.rake
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: setup_first_stats'
|
||||||
|
task setup_first_stats: :environment do
|
||||||
|
Stat.update_stats
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord
|
||||||
|
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: fix_types_de_champ_revisions'
|
||||||
|
task fix_types_de_champ_revisions: :environment do
|
||||||
|
puts "Running deploy task 'fix_types_de_champ_revisions'"
|
||||||
|
|
||||||
|
types_de_champ = TypeDeChamp.joins(:parent).where('types_de_champ.revision_id != parents_types_de_champ.revision_id')
|
||||||
|
progress = ProgressReport.new(types_de_champ.count)
|
||||||
|
types_de_champ.find_each do |type_de_champ|
|
||||||
|
type_de_champ.update_column(:revision_id, type_de_champ.parent.revision_id)
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
# Update task as completed. If you remove the line below, the task will
|
||||||
|
# run with every deploy (or every time you call after_party:run).
|
||||||
|
AfterParty::TaskRecord
|
||||||
|
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
|
@ -54,6 +54,7 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
||||||
"@typescript-eslint/parser": "^5.8.1",
|
"@typescript-eslint/parser": "^5.8.1",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
|
"del-cli": "^4.0.1",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
"webpack-dev-server": "^4.6.0"
|
"webpack-dev-server": "^4.6.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"clean": "del tmp public/packs public/packs-test",
|
||||||
"lint:js": "eslint --ext .js,.jsx,.ts,.tsx ./app/javascript ./config/webpack",
|
"lint:js": "eslint --ext .js,.jsx,.ts,.tsx ./app/javascript ./config/webpack",
|
||||||
"webpack:build": "NODE_ENV=production bin/webpack",
|
"webpack:build": "NODE_ENV=production bin/webpack",
|
||||||
"lint:types": "tsc",
|
"lint:types": "tsc",
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
include ActionDispatch::TestProcess
|
||||||
|
|
||||||
|
describe Administrateurs::DossierSubmittedMessagesController, type: :controller do
|
||||||
|
let(:administrateur) { create(:administrateur) }
|
||||||
|
|
||||||
|
before { sign_in(administrateur.user) }
|
||||||
|
|
||||||
|
describe '#create' do
|
||||||
|
context 'when procedure is not published' do
|
||||||
|
let(:procedure) { create(:procedure, administrateur: administrateur) }
|
||||||
|
|
||||||
|
it 'creates a DossierSubmittedMessage on draft_revision' do
|
||||||
|
message_on_submit_by_usager = "hello"
|
||||||
|
expect {
|
||||||
|
post(:create, params: { procedure_id: procedure.id, dossier_submitted_message: { message_on_submit_by_usager: message_on_submit_by_usager } })
|
||||||
|
}.to change { DossierSubmittedMessage.count }.by(1)
|
||||||
|
expect(response).to redirect_to admin_procedure_path(procedure)
|
||||||
|
expect(procedure.reload.draft_revision.dossier_submitted_message).to eq(DossierSubmittedMessage.first)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when procedure is published' do
|
||||||
|
let(:procedure) { create(:procedure, :published, administrateur: administrateur) }
|
||||||
|
|
||||||
|
it 'creates a DossierSubmittedMessage on published_revision' do
|
||||||
|
message_on_submit_by_usager = "hello"
|
||||||
|
expect {
|
||||||
|
post(:create, params: { procedure_id: procedure.id, dossier_submitted_message: { message_on_submit_by_usager: message_on_submit_by_usager } })
|
||||||
|
}.to change { DossierSubmittedMessage.count }.by(1)
|
||||||
|
expect(response).to redirect_to admin_procedure_path(procedure)
|
||||||
|
expect(procedure.reload.published_revision.dossier_submitted_message).to eq(DossierSubmittedMessage.first)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#edit' do
|
||||||
|
context 'when procedure is draft and have a DossierSubmittedMessage' do
|
||||||
|
let(:procedure) { create(:procedure, :with_dossier_submitted_message, administrateur: administrateur) }
|
||||||
|
|
||||||
|
it 'assigns the existing DossierSubmittedMessage' do
|
||||||
|
get(:edit, params: { procedure_id: procedure.id })
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(assigns(:dossier_submitted_message)).to eq(procedure.active_dossier_submitted_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when draft procedure does not have dossier_submitted_message' do
|
||||||
|
let(:procedure) { create(:procedure, administrateur: administrateur) }
|
||||||
|
|
||||||
|
it 'builds a new DossierSubmittedMessage' do
|
||||||
|
get(:edit, params: { procedure_id: procedure.id })
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(assigns(:dossier_submitted_message).persisted?).to eq(false)
|
||||||
|
expect(assigns(:dossier_submitted_message)).to be_an_instance_of(DossierSubmittedMessage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#update' do
|
||||||
|
context 'when procedure is draft' do
|
||||||
|
let(:procedure) { create(:procedure, :with_dossier_submitted_message, administrateur: administrateur) }
|
||||||
|
|
||||||
|
it 'updates the existing DossierSubmittedMessage on draft_revision' do
|
||||||
|
new_message_on_submit_by_usager = "hello"
|
||||||
|
patch(:update, params: { procedure_id: procedure.id, dossier_submitted_message: { message_on_submit_by_usager: new_message_on_submit_by_usager } })
|
||||||
|
expect(response).to redirect_to admin_procedure_path(procedure)
|
||||||
|
expect(procedure.draft_revision.dossier_submitted_message.message_on_submit_by_usager).to eq(new_message_on_submit_by_usager)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when draft procedure is published' do
|
||||||
|
let(:procedure) { create(:procedure, :published, :with_dossier_submitted_message, administrateur: administrateur) }
|
||||||
|
it 'updates the existing DossierSubmittedMessage on published_revision' do
|
||||||
|
new_message_on_submit_by_usager = "hello"
|
||||||
|
patch(:update, params: { procedure_id: procedure.id, dossier_submitted_message: { message_on_submit_by_usager: new_message_on_submit_by_usager } })
|
||||||
|
expect(response).to redirect_to admin_procedure_path(procedure)
|
||||||
|
expect(procedure.published_revision.dossier_submitted_message.message_on_submit_by_usager).to eq(new_message_on_submit_by_usager)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -25,18 +25,31 @@ describe Experts::AvisController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#procedure' do
|
describe '#procedure' do
|
||||||
before { get :procedure, params: { procedure_id: procedure.id } }
|
context 'without filter' do
|
||||||
|
before { get :procedure, params: { procedure_id: procedure.id } }
|
||||||
|
|
||||||
it { expect(response).to have_http_status(:success) }
|
it { expect(response).to have_http_status(:success) }
|
||||||
it { expect(assigns(:avis_a_donner)).to match([avis_without_answer]) }
|
it { expect(assigns(:avis_a_donner)).to match([avis_without_answer]) }
|
||||||
it { expect(assigns(:avis_donnes)).to match([avis_with_answer]) }
|
it { expect(assigns(:avis_donnes)).to match([avis_with_answer]) }
|
||||||
it { expect(assigns(:statut)).to eq('a-donner') }
|
it { expect(assigns(:statut)).to eq('a-donner') }
|
||||||
|
end
|
||||||
|
|
||||||
context 'with a statut equal to donnes' do
|
context 'with a statut equal to donnes' do
|
||||||
before { get :procedure, params: { statut: 'donnes', procedure_id: procedure.id } }
|
before { get :procedure, params: { statut: 'donnes', procedure_id: procedure.id } }
|
||||||
|
|
||||||
it { expect(assigns(:statut)).to eq('donnes') }
|
it { expect(assigns(:statut)).to eq('donnes') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with different procedure' do
|
||||||
|
subject { get :procedure, params: { statut: 'donnes', procedure_id: procedure.id } }
|
||||||
|
|
||||||
|
it 'fails' do
|
||||||
|
sign_in(create(:expert).user)
|
||||||
|
subject
|
||||||
|
expect(response).to redirect_to(expert_all_avis_path)
|
||||||
|
expect(flash.alert).to eq("Vous n’avez pas accès à cette démarche.")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#bilans_bdf' do
|
describe '#bilans_bdf' do
|
||||||
|
@ -64,22 +77,52 @@ describe Experts::AvisController, type: :controller do
|
||||||
expect(response).to redirect_to(root_path)
|
expect(response).to redirect_to(root_path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with an avis that does not belongs to current_expert' do
|
||||||
|
it "refuse l'accès au dossier" do
|
||||||
|
sign_in(create(:expert).user)
|
||||||
|
subject
|
||||||
|
expect(response).to redirect_to(expert_all_avis_path)
|
||||||
|
expect(flash.alert).to eq("Vous n’avez pas accès à cet avis.")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#instruction' do
|
describe '#instruction' do
|
||||||
before { get :instruction, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
subject { get :instruction, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
||||||
|
context 'with valid avis' do
|
||||||
it { expect(response).to have_http_status(:success) }
|
before { subject }
|
||||||
it { expect(assigns(:avis)).to eq(avis_without_answer) }
|
it { expect(response).to have_http_status(:success) }
|
||||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
it { expect(assigns(:avis)).to eq(avis_without_answer) }
|
||||||
|
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||||
|
end
|
||||||
|
context 'with an avis that does not belongs to current_expert' do
|
||||||
|
it "refuse l'accès au dossier" do
|
||||||
|
sign_in(create(:expert).user)
|
||||||
|
subject
|
||||||
|
expect(response).to redirect_to(expert_all_avis_path)
|
||||||
|
expect(flash.alert).to eq("Vous n’avez pas accès à cet avis.")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#messagerie' do
|
describe '#messagerie' do
|
||||||
before { get :messagerie, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
subject { get :messagerie, params: { id: avis_without_answer.id, procedure_id: procedure.id } }
|
||||||
|
context 'with valid avis' do
|
||||||
|
before { subject }
|
||||||
|
|
||||||
it { expect(response).to have_http_status(:success) }
|
it { expect(response).to have_http_status(:success) }
|
||||||
it { expect(assigns(:avis)).to eq(avis_without_answer) }
|
it { expect(assigns(:avis)).to eq(avis_without_answer) }
|
||||||
it { expect(assigns(:dossier)).to eq(dossier) }
|
it { expect(assigns(:dossier)).to eq(dossier) }
|
||||||
|
end
|
||||||
|
context 'with an avis that does not belongs to current_expert' do
|
||||||
|
it "refuse l'accès au dossier" do
|
||||||
|
sign_in(create(:expert).user)
|
||||||
|
subject
|
||||||
|
expect(response).to redirect_to(expert_all_avis_path)
|
||||||
|
expect(flash.alert).to eq("Vous n’avez pas accès à cet avis.")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#update' do
|
describe '#update' do
|
||||||
|
@ -118,6 +161,14 @@ describe Experts::AvisController, type: :controller do
|
||||||
expect(flash.notice).to eq('Votre réponse est enregistrée.')
|
expect(flash.notice).to eq('Votre réponse est enregistrée.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
context 'with an avis that does not belongs to current_expert' do
|
||||||
|
it "refuse l'accès au dossier" do
|
||||||
|
sign_in(create(:expert).user)
|
||||||
|
patch :update, params: { id: avis_without_answer.id, procedure_id: procedure.id, avis: { answer: 'answer' } }
|
||||||
|
expect(response).to redirect_to(expert_all_avis_path)
|
||||||
|
expect(flash.alert).to eq("Vous n’avez pas accès à cet avis.")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#create_commentaire' do
|
describe '#create_commentaire' do
|
||||||
|
|
5
spec/factories/dossier_submitted_message.rb
Normal file
5
spec/factories/dossier_submitted_message.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
FactoryBot.define do
|
||||||
|
factory :dossier_submitted_message do
|
||||||
|
message_on_submit_by_usager { "BAM !" }
|
||||||
|
end
|
||||||
|
end
|
|
@ -24,10 +24,11 @@ FactoryBot.define do
|
||||||
types_de_champ_private { [] }
|
types_de_champ_private { [] }
|
||||||
updated_at { nil }
|
updated_at { nil }
|
||||||
attestation_template { nil }
|
attestation_template { nil }
|
||||||
|
dossier_submitted_message { nil }
|
||||||
end
|
end
|
||||||
|
|
||||||
after(:build) do |procedure, evaluator|
|
after(:build) do |procedure, evaluator|
|
||||||
initial_revision = build(:procedure_revision, procedure: procedure, attestation_template: evaluator.attestation_template)
|
initial_revision = build(:procedure_revision, procedure: procedure, attestation_template: evaluator.attestation_template, dossier_submitted_message: evaluator.dossier_submitted_message)
|
||||||
add_types_de_champs(evaluator.types_de_champ, to: initial_revision, scope: :public)
|
add_types_de_champs(evaluator.types_de_champ, to: initial_revision, scope: :public)
|
||||||
add_types_de_champs(evaluator.types_de_champ_private, to: initial_revision, scope: :private)
|
add_types_de_champs(evaluator.types_de_champ_private, to: initial_revision, scope: :private)
|
||||||
|
|
||||||
|
@ -319,6 +320,12 @@ FactoryBot.define do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :with_dossier_submitted_message do
|
||||||
|
after(:build) do |procedure, _evaluator|
|
||||||
|
build(:dossier_submitted_message, revisions: [procedure.active_revision])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
describe '20200708101123_add_default_skip_validation_to_piece_justificative.rake' do
|
||||||
|
let(:rake_task) { Rake::Task['after_party:add_default_skip_validation_to_piece_justificative'] }
|
||||||
|
let!(:pj_type_de_champ) { create(:type_de_champ_piece_justificative) }
|
||||||
|
let!(:text_type_de_champ) { create(:type_de_champ_text) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
rake_task.invoke
|
||||||
|
text_type_de_champ.reload
|
||||||
|
pj_type_de_champ.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
after { rake_task.reenable }
|
||||||
|
|
||||||
|
context 'on a piece_justificative type de champ' do
|
||||||
|
it 'sets the skip_pj_validation option' do
|
||||||
|
expect(pj_type_de_champ.skip_pj_validation).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'on a non piece_justificative type de champ' do
|
||||||
|
it 'does not set the skip_pj_validation option' do
|
||||||
|
expect(text_type_de_champ.skip_pj_validation).to be_blank
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,60 @@
|
||||||
|
describe '20201001161931_migrate_filters_to_use_stable_id' do
|
||||||
|
let(:rake_task) { Rake::Task['after_party:migrate_filters_to_use_stable_id'] }
|
||||||
|
|
||||||
|
let(:procedure) { create(:procedure, :with_instructeur, :with_type_de_champ) }
|
||||||
|
let(:type_de_champ) { procedure.types_de_champ.first }
|
||||||
|
let(:sort) do
|
||||||
|
{
|
||||||
|
"table" => "type_de_champ",
|
||||||
|
"column" => type_de_champ.id.to_s,
|
||||||
|
"order" => "asc"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let(:filters) do
|
||||||
|
{
|
||||||
|
'tous' => [
|
||||||
|
{
|
||||||
|
"label" => "test",
|
||||||
|
"table" => "type_de_champ",
|
||||||
|
"column" => type_de_champ.id.to_s,
|
||||||
|
"value" => "test"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'suivis' => [],
|
||||||
|
'traites' => [],
|
||||||
|
'a-suivre' => [],
|
||||||
|
'archives' => []
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let(:displayed_fields) do
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"label" => "test",
|
||||||
|
"table" => "type_de_champ",
|
||||||
|
"column" => type_de_champ.id.to_s
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
let!(:procedure_presentation) do
|
||||||
|
type_de_champ.update_column(:stable_id, 13)
|
||||||
|
procedure_presentation = create(:procedure_presentation, procedure: procedure, assign_to: procedure.groupe_instructeurs.first.assign_tos.first)
|
||||||
|
procedure_presentation.update_columns(sort: sort, filters: filters, displayed_fields: displayed_fields)
|
||||||
|
procedure_presentation
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
rake_task.invoke
|
||||||
|
procedure_presentation.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
after { rake_task.reenable }
|
||||||
|
|
||||||
|
context "should migrate procedure_presentation" do
|
||||||
|
it "columns are updated" do
|
||||||
|
expect(procedure_presentation.sort['column']).to eq(type_de_champ.stable_id.to_s)
|
||||||
|
expect(procedure_presentation.filters['tous'][0]['column']).to eq(type_de_champ.stable_id.to_s)
|
||||||
|
expect(procedure_presentation.displayed_fields[0]['column']).to eq(type_de_champ.stable_id.to_s)
|
||||||
|
expect(procedure_presentation.filters['migrated']).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -27,15 +27,23 @@ RSpec.describe DossierMailer, type: :mailer do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.notify_new_answer with dossier brouillon' do
|
describe '.notify_new_answer with dossier brouillon' do
|
||||||
let(:dossier) { create(:dossier, procedure: create(:simple_procedure)) }
|
let(:service) { build(:service) }
|
||||||
|
let(:procedure) { create(:simple_procedure, service: service) }
|
||||||
|
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
let(:commentaire) { create(:commentaire, dossier: dossier) }
|
let(:commentaire) { create(:commentaire, dossier: dossier) }
|
||||||
subject { described_class.with(commentaire: commentaire).notify_new_answer }
|
subject { described_class.with(commentaire: commentaire).notify_new_answer }
|
||||||
|
|
||||||
it { expect(subject.subject).to include("Nouveau message") }
|
it { expect(subject.subject).to include("Nouveau message") }
|
||||||
it { expect(subject.subject).to include(dossier.id.to_s) }
|
it { expect(subject.subject).to include(dossier.id.to_s) }
|
||||||
|
it { expect(subject.body).to include(dossier.procedure.service.email) }
|
||||||
it { expect(subject.body).not_to include(messagerie_dossier_url(dossier)) }
|
it { expect(subject.body).not_to include(messagerie_dossier_url(dossier)) }
|
||||||
|
|
||||||
it_behaves_like 'a dossier notification'
|
it_behaves_like 'a dossier notification'
|
||||||
|
|
||||||
|
context 'when there is no associated service' do
|
||||||
|
let(:service) { nil }
|
||||||
|
it { expect { subject }.not_to raise_error }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.notify_new_answer with dossier en construction' do
|
describe '.notify_new_answer with dossier en construction' do
|
||||||
|
|
|
@ -5,7 +5,7 @@ class DossierMailerPreview < ActionMailer::Preview
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_new_answer
|
def notify_new_answer
|
||||||
DossierMailer.notify_new_answer(dossier)
|
DossierMailer.with(commentaire: commentaire(on: draft)).notify_new_answer
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_revert_to_instruction
|
def notify_revert_to_instruction
|
||||||
|
@ -88,7 +88,7 @@ class DossierMailerPreview < ActionMailer::Preview
|
||||||
end
|
end
|
||||||
|
|
||||||
def draft
|
def draft
|
||||||
Dossier.new(id: 47882, procedure: procedure, user: user)
|
Dossier.new(id: 47882, state: :brouillon, procedure: procedure, user: user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def dossier
|
def dossier
|
||||||
|
@ -119,4 +119,9 @@ class DossierMailerPreview < ActionMailer::Preview
|
||||||
def transfer
|
def transfer
|
||||||
DossierTransfer.new(email: usager_email, dossiers: [dossier, dossier_accepte])
|
DossierTransfer.new(email: usager_email, dossiers: [dossier, dossier_accepte])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def commentaire(on:)
|
||||||
|
dossier = on
|
||||||
|
Commentaire.new(id: 7726, body: "Bonjour, Vous avez commencé le dépôt d’un dossier pour une subvention DETR /DSIL. Dans le cas où votre opération n’aurait pas connu un commencement d’exécution, vous êtes encouragé(e) à redéposer un nouveau dossier sur le formulaire de cette année.\nLa DDT", dossier: dossier)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1573,6 +1573,158 @@ describe Dossier do
|
||||||
it { expect(dossier.spreadsheet_columns(types_de_champ: [])).to include(["État du dossier", "Brouillon"]) }
|
it { expect(dossier.spreadsheet_columns(types_de_champ: [])).to include(["État du dossier", "Brouillon"]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#can_rebase?' do
|
||||||
|
let(:procedure) { create(:procedure, :with_type_de_champ_mandatory, :with_yes_no, attestation_template: build(:attestation_template)) }
|
||||||
|
let(:attestation_template) { procedure.draft_revision.attestation_template.find_or_revise! }
|
||||||
|
let(:type_de_champ) { procedure.types_de_champ.find { |tdc| !tdc.mandatory? } }
|
||||||
|
let(:mandatory_type_de_champ) { procedure.types_de_champ.find(&:mandatory?) }
|
||||||
|
|
||||||
|
before { Flipper.enable(:procedure_revisions, procedure) }
|
||||||
|
|
||||||
|
context 'en_construction' do
|
||||||
|
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
procedure.publish!
|
||||||
|
procedure.reload
|
||||||
|
dossier
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with added type de champ' do
|
||||||
|
before do
|
||||||
|
procedure.draft_revision.add_type_de_champ({
|
||||||
|
type_champ: TypeDeChamp.type_champs.fetch(:text),
|
||||||
|
libelle: "Un champ text"
|
||||||
|
})
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be false' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with type de champ made optional' do
|
||||||
|
before do
|
||||||
|
procedure.draft_revision.find_or_clone_type_de_champ(mandatory_type_de_champ.stable_id).update(mandatory: false)
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be true' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with type de champ made mandatory' do
|
||||||
|
before do
|
||||||
|
procedure.draft_revision.find_or_clone_type_de_champ(type_de_champ.stable_id).update(mandatory: true)
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be false' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with removed type de champ' do
|
||||||
|
before do
|
||||||
|
procedure.draft_revision.remove_type_de_champ(type_de_champ.stable_id)
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be true' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with attestation template changes' do
|
||||||
|
before do
|
||||||
|
attestation_template.update(title: "Test")
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be true' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'en_instruction' do
|
||||||
|
let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
procedure.publish!
|
||||||
|
procedure.reload
|
||||||
|
dossier
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with added type de champ' do
|
||||||
|
before do
|
||||||
|
procedure.draft_revision.add_type_de_champ({
|
||||||
|
type_champ: TypeDeChamp.type_champs.fetch(:text),
|
||||||
|
libelle: "Un champ text"
|
||||||
|
})
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be false' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with removed type de champ' do
|
||||||
|
before do
|
||||||
|
procedure.draft_revision.remove_type_de_champ(type_de_champ.stable_id)
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be false' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with attestation template changes' do
|
||||||
|
before do
|
||||||
|
attestation_template.update(title: "Test")
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be true' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with type de champ made optional' do
|
||||||
|
before do
|
||||||
|
procedure.draft_revision.find_or_clone_type_de_champ(mandatory_type_de_champ.stable_id).update(mandatory: false)
|
||||||
|
procedure.publish_revision!
|
||||||
|
dossier.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be false' do
|
||||||
|
expect(dossier.pending_changes).not_to be_empty
|
||||||
|
expect(dossier.can_rebase?).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#rebase" do
|
describe "#rebase" do
|
||||||
let(:procedure) { create(:procedure, :with_type_de_champ_mandatory, :with_yes_no, :with_repetition, :with_datetime) }
|
let(:procedure) { create(:procedure, :with_type_de_champ_mandatory, :with_yes_no, :with_repetition, :with_datetime) }
|
||||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
|
|
|
@ -825,13 +825,15 @@ describe Procedure do
|
||||||
context 'when the procedure has dossiers' do
|
context 'when the procedure has dossiers' do
|
||||||
let(:dossier_draft) { create(:dossier, :brouillon, procedure: procedure) }
|
let(:dossier_draft) { create(:dossier, :brouillon, procedure: procedure) }
|
||||||
let(:dossier_submitted) { create(:dossier, :en_construction, procedure: procedure) }
|
let(:dossier_submitted) { create(:dossier, :en_construction, procedure: procedure) }
|
||||||
|
let(:dossier_termine) { create(:dossier, :accepte, procedure: procedure) }
|
||||||
|
|
||||||
before { [dossier_draft, dossier_submitted] }
|
before { [dossier_draft, dossier_submitted, dossier_termine] }
|
||||||
|
|
||||||
it 'enqueues rebase jobs for draft dossiers' do
|
it 'enqueues rebase jobs for draft dossiers' do
|
||||||
subject
|
subject
|
||||||
expect(DossierRebaseJob).to have_been_enqueued.with(dossier_draft)
|
expect(DossierRebaseJob).to have_been_enqueued.with(dossier_draft)
|
||||||
expect(DossierRebaseJob).not_to have_been_enqueued.with(dossier_submitted)
|
expect(DossierRebaseJob).to have_been_enqueued.with(dossier_submitted)
|
||||||
|
expect(DossierRebaseJob).not_to have_been_enqueued.with(dossier_termine)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -433,7 +433,7 @@ describe User, type: :model do
|
||||||
it 'transfers the dossier' do
|
it 'transfers the dossier' do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(targeted_user.dossiers.with_discarded).to match([dossier, hidden_dossier])
|
expect(targeted_user.dossiers.with_discarded).to contain_exactly(dossier, hidden_dossier)
|
||||||
expect(targeted_user.invites).to match([invite])
|
expect(targeted_user.invites).to match([invite])
|
||||||
expect(targeted_user.merge_logs.first).to eq(merge_log)
|
expect(targeted_user.merge_logs.first).to eq(merge_log)
|
||||||
|
|
||||||
|
|
176
yarn.lock
176
yarn.lock
|
@ -2442,6 +2442,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
|
||||||
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
|
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
|
||||||
|
|
||||||
|
"@types/minimist@^1.2.2":
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
|
||||||
|
integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
|
||||||
|
|
||||||
"@types/node-fetch@^2.1.6":
|
"@types/node-fetch@^2.1.6":
|
||||||
version "2.5.12"
|
version "2.5.12"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66"
|
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66"
|
||||||
|
@ -3224,6 +3229,11 @@ array.prototype.flatmap@^1.2.5:
|
||||||
define-properties "^1.1.3"
|
define-properties "^1.1.3"
|
||||||
es-abstract "^1.19.0"
|
es-abstract "^1.19.0"
|
||||||
|
|
||||||
|
arrify@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
|
||||||
|
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
|
||||||
|
|
||||||
arrify@^2.0.1:
|
arrify@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
|
resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
|
||||||
|
@ -3947,6 +3957,16 @@ callsites@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||||
|
|
||||||
|
camelcase-keys@^7.0.0:
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-7.0.2.tgz#d048d8c69448745bb0de6fc4c1c52a30dfbe7252"
|
||||||
|
integrity sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==
|
||||||
|
dependencies:
|
||||||
|
camelcase "^6.3.0"
|
||||||
|
map-obj "^4.1.0"
|
||||||
|
quick-lru "^5.1.1"
|
||||||
|
type-fest "^1.2.1"
|
||||||
|
|
||||||
camelcase@^5.0.0, camelcase@^5.3.1:
|
camelcase@^5.0.0, camelcase@^5.3.1:
|
||||||
version "5.3.1"
|
version "5.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
|
||||||
|
@ -3957,6 +3977,11 @@ camelcase@^6.0.0, camelcase@^6.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.1.tgz#250fd350cfd555d0d2160b1d51510eaf8326e86e"
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.1.tgz#250fd350cfd555d0d2160b1d51510eaf8326e86e"
|
||||||
integrity sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==
|
integrity sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==
|
||||||
|
|
||||||
|
camelcase@^6.3.0:
|
||||||
|
version "6.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
|
||||||
|
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
|
||||||
|
|
||||||
caniuse-api@^3.0.0:
|
caniuse-api@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
|
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
|
||||||
|
@ -4943,11 +4968,24 @@ decache@^4.6.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
callsite "^1.0.0"
|
callsite "^1.0.0"
|
||||||
|
|
||||||
decamelize@^1.2.0:
|
decamelize-keys@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
|
||||||
|
integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=
|
||||||
|
dependencies:
|
||||||
|
decamelize "^1.1.0"
|
||||||
|
map-obj "^1.0.0"
|
||||||
|
|
||||||
|
decamelize@^1.1.0, decamelize@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||||
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
||||||
|
|
||||||
|
decamelize@^5.0.0:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9"
|
||||||
|
integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==
|
||||||
|
|
||||||
decode-uri-component@^0.2.0:
|
decode-uri-component@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||||
|
@ -5105,6 +5143,14 @@ define-property@^2.0.2:
|
||||||
is-descriptor "^1.0.2"
|
is-descriptor "^1.0.2"
|
||||||
isobject "^3.0.1"
|
isobject "^3.0.1"
|
||||||
|
|
||||||
|
del-cli@^4.0.1:
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/del-cli/-/del-cli-4.0.1.tgz#2303ccaa45708ee8c6211568344cf87336abf30a"
|
||||||
|
integrity sha512-KtR/6cBfZkGDAP2NA7z+bP4p1OMob3wjN9mq13+SWvExx6jT9gFWfLgXEeX8J2B47OKeNCq9yTONmtryQ+m+6g==
|
||||||
|
dependencies:
|
||||||
|
del "^6.0.0"
|
||||||
|
meow "^10.1.0"
|
||||||
|
|
||||||
del@^5.1.0:
|
del@^5.1.0:
|
||||||
version "5.1.0"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7"
|
resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7"
|
||||||
|
@ -6916,6 +6962,11 @@ har-validator@~5.1.3:
|
||||||
ajv "^6.12.3"
|
ajv "^6.12.3"
|
||||||
har-schema "^2.0.0"
|
har-schema "^2.0.0"
|
||||||
|
|
||||||
|
hard-rejection@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
|
||||||
|
integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
|
||||||
|
|
||||||
has-ansi@^0.1.0:
|
has-ansi@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e"
|
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e"
|
||||||
|
@ -7102,6 +7153,13 @@ hosted-git-info@^2.1.4:
|
||||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
|
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
|
||||||
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
|
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
|
||||||
|
|
||||||
|
hosted-git-info@^4.0.1:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224"
|
||||||
|
integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==
|
||||||
|
dependencies:
|
||||||
|
lru-cache "^6.0.0"
|
||||||
|
|
||||||
hpack.js@^2.1.6:
|
hpack.js@^2.1.6:
|
||||||
version "2.1.6"
|
version "2.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
|
resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
|
||||||
|
@ -7340,6 +7398,11 @@ indent-string@^4.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
|
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
|
||||||
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
|
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
|
||||||
|
|
||||||
|
indent-string@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5"
|
||||||
|
integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==
|
||||||
|
|
||||||
indexes-of@^1.0.1:
|
indexes-of@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
|
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
|
||||||
|
@ -7571,6 +7634,13 @@ is-core-module@^2.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
|
|
||||||
|
is-core-module@^2.5.0:
|
||||||
|
version "2.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
|
||||||
|
integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
|
||||||
|
dependencies:
|
||||||
|
has "^1.0.3"
|
||||||
|
|
||||||
is-data-descriptor@^0.1.4:
|
is-data-descriptor@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
|
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
|
||||||
|
@ -7752,7 +7822,7 @@ is-path-inside@^3.0.1, is-path-inside@^3.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
|
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
|
||||||
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
|
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
|
||||||
|
|
||||||
is-plain-obj@^1.0.0:
|
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||||
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
|
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
|
||||||
|
@ -8161,7 +8231,7 @@ kind-of@^5.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
|
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
|
||||||
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
|
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
|
||||||
|
|
||||||
kind-of@^6.0.0, kind-of@^6.0.2:
|
kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
|
||||||
version "6.0.3"
|
version "6.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
||||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||||
|
@ -8553,6 +8623,11 @@ map-cache@^0.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
|
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
|
||||||
integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
|
integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
|
||||||
|
|
||||||
|
map-obj@^1.0.0:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
|
||||||
|
integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
|
||||||
|
|
||||||
map-obj@^4.0.0, map-obj@^4.1.0, map-obj@^4.2.1:
|
map-obj@^4.0.0, map-obj@^4.1.0, map-obj@^4.2.1:
|
||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a"
|
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a"
|
||||||
|
@ -8681,6 +8756,24 @@ memory-fs@^0.5.0:
|
||||||
errno "^0.1.3"
|
errno "^0.1.3"
|
||||||
readable-stream "^2.0.1"
|
readable-stream "^2.0.1"
|
||||||
|
|
||||||
|
meow@^10.1.0:
|
||||||
|
version "10.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/meow/-/meow-10.1.2.tgz#62951cb69afa69594142c8250806bc30a3912e4d"
|
||||||
|
integrity sha512-zbuAlN+V/sXlbGchNS9WTWjUzeamwMt/BApKCJi7B0QyZstZaMx0n4Unll/fg0njGtMdC9UP5SAscvOCLYdM+Q==
|
||||||
|
dependencies:
|
||||||
|
"@types/minimist" "^1.2.2"
|
||||||
|
camelcase-keys "^7.0.0"
|
||||||
|
decamelize "^5.0.0"
|
||||||
|
decamelize-keys "^1.1.0"
|
||||||
|
hard-rejection "^2.1.0"
|
||||||
|
minimist-options "4.1.0"
|
||||||
|
normalize-package-data "^3.0.2"
|
||||||
|
read-pkg-up "^8.0.0"
|
||||||
|
redent "^4.0.0"
|
||||||
|
trim-newlines "^4.0.2"
|
||||||
|
type-fest "^1.2.2"
|
||||||
|
yargs-parser "^20.2.9"
|
||||||
|
|
||||||
merge-descriptors@1.0.1:
|
merge-descriptors@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||||
|
@ -8800,6 +8893,11 @@ mimic-response@^2.0.0, mimic-response@^2.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
|
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
|
||||||
integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
|
integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
|
||||||
|
|
||||||
|
min-indent@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||||
|
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
||||||
|
|
||||||
mini-css-extract-plugin@^0.9.0:
|
mini-css-extract-plugin@^0.9.0:
|
||||||
version "0.9.0"
|
version "0.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e"
|
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e"
|
||||||
|
@ -8827,6 +8925,15 @@ minimatch@^3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^1.1.7"
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
|
minimist-options@4.1.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
|
||||||
|
integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
|
||||||
|
dependencies:
|
||||||
|
arrify "^1.0.1"
|
||||||
|
is-plain-obj "^1.1.0"
|
||||||
|
kind-of "^6.0.3"
|
||||||
|
|
||||||
minimist@^1.2.0, minimist@^1.2.5:
|
minimist@^1.2.0, minimist@^1.2.5:
|
||||||
version "1.2.5"
|
version "1.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||||
|
@ -9361,6 +9468,16 @@ normalize-package-data@^2.5.0:
|
||||||
semver "2 || 3 || 4 || 5"
|
semver "2 || 3 || 4 || 5"
|
||||||
validate-npm-package-license "^3.0.1"
|
validate-npm-package-license "^3.0.1"
|
||||||
|
|
||||||
|
normalize-package-data@^3.0.2:
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e"
|
||||||
|
integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==
|
||||||
|
dependencies:
|
||||||
|
hosted-git-info "^4.0.1"
|
||||||
|
is-core-module "^2.5.0"
|
||||||
|
semver "^7.3.4"
|
||||||
|
validate-npm-package-license "^3.0.1"
|
||||||
|
|
||||||
normalize-path@^2.1.1:
|
normalize-path@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
|
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
|
||||||
|
@ -9957,7 +10074,7 @@ parse-json@^4.0.0:
|
||||||
error-ex "^1.3.1"
|
error-ex "^1.3.1"
|
||||||
json-parse-better-errors "^1.0.1"
|
json-parse-better-errors "^1.0.1"
|
||||||
|
|
||||||
parse-json@^5.0.0:
|
parse-json@^5.0.0, parse-json@^5.2.0:
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
|
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
|
||||||
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
|
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
|
||||||
|
@ -11095,6 +11212,11 @@ queue-microtask@^1.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||||
|
|
||||||
|
quick-lru@^5.1.1:
|
||||||
|
version "5.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
||||||
|
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
||||||
|
|
||||||
quickselect@^2.0.0:
|
quickselect@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
|
resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
|
||||||
|
@ -11241,6 +11363,15 @@ read-pkg-up@^7.0.1:
|
||||||
read-pkg "^5.2.0"
|
read-pkg "^5.2.0"
|
||||||
type-fest "^0.8.1"
|
type-fest "^0.8.1"
|
||||||
|
|
||||||
|
read-pkg-up@^8.0.0:
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-8.0.0.tgz#72f595b65e66110f43b052dd9af4de6b10534670"
|
||||||
|
integrity sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==
|
||||||
|
dependencies:
|
||||||
|
find-up "^5.0.0"
|
||||||
|
read-pkg "^6.0.0"
|
||||||
|
type-fest "^1.0.1"
|
||||||
|
|
||||||
read-pkg@^5.2.0:
|
read-pkg@^5.2.0:
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
|
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
|
||||||
|
@ -11251,6 +11382,16 @@ read-pkg@^5.2.0:
|
||||||
parse-json "^5.0.0"
|
parse-json "^5.0.0"
|
||||||
type-fest "^0.6.0"
|
type-fest "^0.6.0"
|
||||||
|
|
||||||
|
read-pkg@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-6.0.0.tgz#a67a7d6a1c2b0c3cd6aa2ea521f40c458a4a504c"
|
||||||
|
integrity sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==
|
||||||
|
dependencies:
|
||||||
|
"@types/normalize-package-data" "^2.4.0"
|
||||||
|
normalize-package-data "^3.0.2"
|
||||||
|
parse-json "^5.2.0"
|
||||||
|
type-fest "^1.0.1"
|
||||||
|
|
||||||
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
|
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
|
||||||
version "2.3.7"
|
version "2.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||||
|
@ -11296,6 +11437,14 @@ readdirp@^3.4.0, readdirp@~3.6.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch "^2.2.1"
|
picomatch "^2.2.1"
|
||||||
|
|
||||||
|
redent@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/redent/-/redent-4.0.0.tgz#0c0ba7caabb24257ab3bb7a4fd95dd1d5c5681f9"
|
||||||
|
integrity sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==
|
||||||
|
dependencies:
|
||||||
|
indent-string "^5.0.0"
|
||||||
|
strip-indent "^4.0.0"
|
||||||
|
|
||||||
regenerate-unicode-properties@^9.0.0:
|
regenerate-unicode-properties@^9.0.0:
|
||||||
version "9.0.0"
|
version "9.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326"
|
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326"
|
||||||
|
@ -12433,6 +12582,13 @@ strip-final-newline@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||||
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
|
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
|
||||||
|
|
||||||
|
strip-indent@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-4.0.0.tgz#b41379433dd06f5eae805e21d631e07ee670d853"
|
||||||
|
integrity sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==
|
||||||
|
dependencies:
|
||||||
|
min-indent "^1.0.1"
|
||||||
|
|
||||||
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
|
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||||
|
@ -12895,6 +13051,11 @@ traverse@~0.6.6:
|
||||||
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
|
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
|
||||||
integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=
|
integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=
|
||||||
|
|
||||||
|
trim-newlines@^4.0.2:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.0.2.tgz#d6aaaf6a0df1b4b536d183879a6b939489808c7c"
|
||||||
|
integrity sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew==
|
||||||
|
|
||||||
trim-repeated@^1.0.0:
|
trim-repeated@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21"
|
resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21"
|
||||||
|
@ -13018,6 +13179,11 @@ type-fest@^0.8.0, type-fest@^0.8.1:
|
||||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||||
|
|
||||||
|
type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
|
||||||
|
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
|
||||||
|
|
||||||
type-is@~1.6.18:
|
type-is@~1.6.18:
|
||||||
version "1.6.18"
|
version "1.6.18"
|
||||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||||
|
@ -13772,7 +13938,7 @@ yargs-parser@^18.1.2:
|
||||||
camelcase "^5.0.0"
|
camelcase "^5.0.0"
|
||||||
decamelize "^1.2.0"
|
decamelize "^1.2.0"
|
||||||
|
|
||||||
yargs-parser@^20.2.2:
|
yargs-parser@^20.2.2, yargs-parser@^20.2.9:
|
||||||
version "20.2.9"
|
version "20.2.9"
|
||||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
|
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
|
||||||
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
|
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
|
||||||
|
|
Loading…
Reference in a new issue