mirror of
https://github.com/docusealco/docuseal
synced 2026-11-04 14:42:32 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94e552d170 | ||
|
|
cf1b0a4c16 | ||
|
|
9aa0a8ecbf | ||
|
|
fd4bef1706 | ||
|
|
d32b0e6d20 | ||
|
|
4a846be214 | ||
|
|
3dd3877ea9 | ||
|
|
b4dba0d809 | ||
|
|
dea80a82d8 | ||
|
|
eefa994724 | ||
|
|
35cce24539 | ||
|
|
e6c8203959 | ||
|
|
9479771fc8 | ||
|
|
711427521c | ||
|
|
5dae742361 | ||
|
|
d8ccd4beee | ||
|
|
c532a0115d | ||
|
|
c9c3364764 | ||
|
|
1ff23d7c40 | ||
|
|
95e9b34033 | ||
|
|
6b42dcf91b | ||
|
|
28962c949b | ||
|
|
4ecbbf8410 | ||
|
|
990b35be18 | ||
|
|
8002764855 | ||
|
|
b80982658c | ||
|
|
443ac23c29 | ||
|
|
37bb987e3e | ||
|
|
c7b08e8d30 | ||
|
|
dd502e8cef | ||
|
|
a554182e57 | ||
|
|
0c039ee64f | ||
|
|
c6b004f107 | ||
|
|
2fcb08d27d | ||
|
|
75fe5ce381 | ||
|
|
fd7d0eaf53 | ||
|
|
7e537e4232 | ||
|
|
a892975010 | ||
|
|
05ec92186b | ||
|
|
8b035f80b3 | ||
|
|
c717293306 | ||
|
|
b3f3cf2aa6 | ||
|
|
7406334f77 | ||
|
|
3e1350a221 | ||
|
|
961e0a1c89 | ||
|
|
2ce9bbecb9 | ||
|
|
704da3a2ec | ||
|
|
2f530ccfca | ||
|
|
e6c20f5ff6 | ||
|
|
d267978437 | ||
|
|
e9d728fa4a | ||
|
|
3c60fb4ee6 | ||
|
|
f1e494b669 | ||
|
|
f7a8e4102b | ||
|
|
311c2b0e34 | ||
|
|
5dd59f4f7c | ||
|
|
571f5d8221 | ||
|
|
136b0eb5ed | ||
|
|
2d813e184b | ||
|
|
fd23674e87 | ||
|
|
3b9d35acf1 | ||
|
|
17fc6e2f1c | ||
|
|
2e132d8b5a | ||
|
|
53bef85a63 | ||
|
|
99ad6e36ac | ||
|
|
bfa41ac35f | ||
|
|
bc4414a368 | ||
|
|
26ae5f1d80 | ||
|
|
be4962a02a | ||
|
|
e72090c2e0 | ||
|
|
ad8bca8bf4 | ||
|
|
22be3b37cf | ||
|
|
cfc32ee522 | ||
|
|
10fbdf6612 | ||
|
|
3604fb6461 | ||
|
|
24392d0258 | ||
|
|
4ab1065773 | ||
|
|
50b0f7e5ed | ||
|
|
be4a0505bc | ||
|
|
bd853c6265 | ||
|
|
5a1efd0e27 | ||
|
|
71b8cc7172 | ||
|
|
126a36dbf3 | ||
|
|
90db64cc03 | ||
|
|
227a067c77 | ||
|
|
dc24df0d4c | ||
|
|
2598962c5b | ||
|
|
b4884e94f6 | ||
|
|
4741e64178 | ||
|
|
25fe35e212 | ||
|
|
92909cea09 | ||
|
|
b16322dd5b | ||
|
|
a04c04141c | ||
|
|
90f21d3ed9 | ||
|
|
f31225e8c2 | ||
|
|
eead1b2bc4 | ||
|
|
f90a4e5576 | ||
|
|
50987ce38b | ||
|
|
26113ac3a6 | ||
|
|
0b7b72ce16 | ||
|
|
95d48b2808 | ||
|
|
8fecf94a28 | ||
|
|
66dd87b290 | ||
|
|
d20e8cc37d | ||
|
|
c189e2ed20 | ||
|
|
57f8f45320 | ||
|
|
5684baf1e0 | ||
|
|
b6f307690d | ||
|
|
66c44f8ff5 | ||
|
|
8f3592c481 | ||
|
|
dc8b1e0741 | ||
|
|
b806a6afc5 | ||
|
|
d43f8f4dd8 | ||
|
|
37c9bf5741 | ||
|
|
a0d37f516f | ||
|
|
2764a18252 | ||
|
|
96cf228e74 | ||
|
|
ff6ff3a51e | ||
|
|
9472a6b5b0 |
No files matched your search
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- name: Install Ruby
|
- name: Install Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.3.3
|
ruby-version: 3.3.4
|
||||||
- name: Cache gems
|
- name: Cache gems
|
||||||
uses: actions/cache@v1
|
uses: actions/cache@v1
|
||||||
with:
|
with:
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
- name: Install Ruby
|
- name: Install Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.3.3
|
ruby-version: 3.3.4
|
||||||
- name: Cache gems
|
- name: Cache gems
|
||||||
uses: actions/cache@v1
|
uses: actions/cache@v1
|
||||||
with:
|
with:
|
||||||
@@ -100,7 +100,7 @@ jobs:
|
|||||||
- name: Install Ruby
|
- name: Install Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.3.3
|
ruby-version: 3.3.4
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ Metrics/MethodLength:
|
|||||||
Max: 30
|
Max: 30
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'db/migrate/**'
|
- 'db/migrate/**'
|
||||||
|
- 'spec/**/*'
|
||||||
|
|
||||||
Metrics/CyclomaticComplexity:
|
Metrics/CyclomaticComplexity:
|
||||||
Max: 15
|
Max: 15
|
||||||
@@ -46,6 +47,8 @@ Layout/LineLength:
|
|||||||
|
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Max: 45
|
Max: 45
|
||||||
|
Exclude:
|
||||||
|
- spec/**/*
|
||||||
|
|
||||||
Metrics/ModuleLength:
|
Metrics/ModuleLength:
|
||||||
Max: 500
|
Max: 500
|
||||||
@@ -65,6 +68,9 @@ RSpec/ExampleLength:
|
|||||||
RSpec/MultipleMemoizedHelpers:
|
RSpec/MultipleMemoizedHelpers:
|
||||||
Max: 6
|
Max: 6
|
||||||
|
|
||||||
|
Metrics/BlockNesting:
|
||||||
|
Max: 4
|
||||||
|
|
||||||
Rails/I18nLocaleTexts:
|
Rails/I18nLocaleTexts:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
FROM ruby:3.3.3-alpine as fonts
|
FROM ruby:3.3.4-alpine as fonts
|
||||||
|
|
||||||
WORKDIR /fonts
|
WORKDIR /fonts
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@ RUN apk --no-cache add fontforge wget && wget https://github.com/satbyy/go-noto-
|
|||||||
|
|
||||||
RUN fontforge -lang=py -c 'font1 = fontforge.open("FreeSans.ttf"); font2 = fontforge.open("NotoSansSymbols2-Regular.ttf"); font1.mergeFonts(font2); font1.generate("FreeSans.ttf")'
|
RUN fontforge -lang=py -c 'font1 = fontforge.open("FreeSans.ttf"); font2 = fontforge.open("NotoSansSymbols2-Regular.ttf"); font1.mergeFonts(font2); font1.generate("FreeSans.ttf")'
|
||||||
|
|
||||||
FROM ruby:3.3.3-alpine as webpack
|
FROM ruby:3.3.4-alpine as webpack
|
||||||
|
|
||||||
ENV RAILS_ENV=production
|
ENV RAILS_ENV=production
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
@@ -32,7 +32,7 @@ COPY ./app/views ./app/views
|
|||||||
|
|
||||||
RUN echo "gem 'shakapacker'" > Gemfile && ./bin/shakapacker
|
RUN echo "gem 'shakapacker'" > Gemfile && ./bin/shakapacker
|
||||||
|
|
||||||
FROM ruby:3.3.3-alpine as app
|
FROM ruby:3.3.4-alpine as app
|
||||||
|
|
||||||
ENV RAILS_ENV=production
|
ENV RAILS_ENV=production
|
||||||
ENV BUNDLE_WITHOUT="development:test"
|
ENV BUNDLE_WITHOUT="development:test"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
ruby '3.3.3'
|
ruby '3.3.4'
|
||||||
|
|
||||||
gem 'arabic-letter-connector', require: 'arabic-letter-connector/logic'
|
gem 'arabic-letter-connector', require: 'arabic-letter-connector/logic'
|
||||||
gem 'aws-sdk-s3', require: false
|
gem 'aws-sdk-s3', require: false
|
||||||
@@ -23,7 +23,6 @@ gem 'image_processing'
|
|||||||
gem 'jwt'
|
gem 'jwt'
|
||||||
gem 'lograge'
|
gem 'lograge'
|
||||||
gem 'mysql2', require: false
|
gem 'mysql2', require: false
|
||||||
gem 'net-smtp', '0.4.0'
|
|
||||||
gem 'oj'
|
gem 'oj'
|
||||||
gem 'pagy'
|
gem 'pagy'
|
||||||
gem 'pg', require: false
|
gem 'pg', require: false
|
||||||
@@ -40,7 +39,7 @@ gem 'ruby-vips'
|
|||||||
gem 'rubyXL'
|
gem 'rubyXL'
|
||||||
gem 'shakapacker'
|
gem 'shakapacker'
|
||||||
gem 'sidekiq'
|
gem 'sidekiq'
|
||||||
gem 'sqlite3', require: false, force_ruby_platform: true
|
gem 'sqlite3', require: false
|
||||||
gem 'strip_attributes'
|
gem 'strip_attributes'
|
||||||
gem 'turbo-rails'
|
gem 'turbo-rails'
|
||||||
gem 'twitter_cldr', require: false
|
gem 'twitter_cldr', require: false
|
||||||
|
|||||||
+186
-182
@@ -1,105 +1,101 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (7.1.3.4)
|
actioncable (7.2.1)
|
||||||
actionpack (= 7.1.3.4)
|
actionpack (= 7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (7.1.3.4)
|
actionmailbox (7.2.1)
|
||||||
actionpack (= 7.1.3.4)
|
actionpack (= 7.2.1)
|
||||||
activejob (= 7.1.3.4)
|
activejob (= 7.2.1)
|
||||||
activerecord (= 7.1.3.4)
|
activerecord (= 7.2.1)
|
||||||
activestorage (= 7.1.3.4)
|
activestorage (= 7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.8.0)
|
||||||
net-imap
|
actionmailer (7.2.1)
|
||||||
net-pop
|
actionpack (= 7.2.1)
|
||||||
net-smtp
|
actionview (= 7.2.1)
|
||||||
actionmailer (7.1.3.4)
|
activejob (= 7.2.1)
|
||||||
actionpack (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
actionview (= 7.1.3.4)
|
mail (>= 2.8.0)
|
||||||
activejob (= 7.1.3.4)
|
|
||||||
activesupport (= 7.1.3.4)
|
|
||||||
mail (~> 2.5, >= 2.5.4)
|
|
||||||
net-imap
|
|
||||||
net-pop
|
|
||||||
net-smtp
|
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (7.1.3.4)
|
actionpack (7.2.1)
|
||||||
actionview (= 7.1.3.4)
|
actionview (= 7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
racc
|
racc
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4, < 3.2)
|
||||||
rack-session (>= 1.0.1)
|
rack-session (>= 1.0.1)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
actiontext (7.1.3.4)
|
useragent (~> 0.16)
|
||||||
actionpack (= 7.1.3.4)
|
actiontext (7.2.1)
|
||||||
activerecord (= 7.1.3.4)
|
actionpack (= 7.2.1)
|
||||||
activestorage (= 7.1.3.4)
|
activerecord (= 7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activestorage (= 7.2.1)
|
||||||
|
activesupport (= 7.2.1)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (7.1.3.4)
|
actionview (7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
activejob (7.1.3.4)
|
activejob (7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (7.1.3.4)
|
activemodel (7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
activerecord (7.1.3.4)
|
activerecord (7.2.1)
|
||||||
activemodel (= 7.1.3.4)
|
activemodel (= 7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (7.1.3.4)
|
activestorage (7.2.1)
|
||||||
actionpack (= 7.1.3.4)
|
actionpack (= 7.2.1)
|
||||||
activejob (= 7.1.3.4)
|
activejob (= 7.2.1)
|
||||||
activerecord (= 7.1.3.4)
|
activerecord (= 7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (7.1.3.4)
|
activesupport (7.2.1)
|
||||||
base64
|
base64
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
connection_pool (>= 2.2.5)
|
connection_pool (>= 2.2.5)
|
||||||
drb
|
drb
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
|
logger (>= 1.4.2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
mutex_m
|
securerandom (>= 0.3)
|
||||||
tzinfo (~> 2.0)
|
tzinfo (~> 2.0, >= 2.0.5)
|
||||||
addressable (2.8.6)
|
addressable (2.8.7)
|
||||||
public_suffix (>= 2.0.2, < 6.0)
|
public_suffix (>= 2.0.2, < 7.0)
|
||||||
annotate (3.2.0)
|
annotate (3.2.0)
|
||||||
activerecord (>= 3.2, < 8.0)
|
activerecord (>= 3.2, < 8.0)
|
||||||
rake (>= 10.4, < 14.0)
|
rake (>= 10.4, < 14.0)
|
||||||
arabic-letter-connector (0.1.1)
|
arabic-letter-connector (0.1.1)
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
aws-eventstream (1.3.0)
|
aws-eventstream (1.3.0)
|
||||||
aws-partitions (1.913.0)
|
aws-partitions (1.985.0)
|
||||||
aws-sdk-core (3.191.6)
|
aws-sdk-core (3.209.1)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.651.0)
|
aws-partitions (~> 1, >= 1.651.0)
|
||||||
aws-sigv4 (~> 1.8)
|
aws-sigv4 (~> 1.9)
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
aws-sdk-kms (1.79.0)
|
aws-sdk-kms (1.94.0)
|
||||||
aws-sdk-core (~> 3, >= 3.191.0)
|
aws-sdk-core (~> 3, >= 3.207.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.146.1)
|
aws-sdk-s3 (1.167.0)
|
||||||
aws-sdk-core (~> 3, >= 3.191.0)
|
aws-sdk-core (~> 3, >= 3.207.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.8)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-secretsmanager (1.91.0)
|
aws-sdk-secretsmanager (1.108.0)
|
||||||
aws-sdk-core (~> 3, >= 3.191.0)
|
aws-sdk-core (~> 3, >= 3.207.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sigv4 (1.8.0)
|
aws-sigv4 (1.10.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
azure-storage-blob (2.0.3)
|
azure-storage-blob (2.0.3)
|
||||||
azure-storage-common (~> 2.0)
|
azure-storage-common (~> 2.0)
|
||||||
@@ -120,14 +116,14 @@ GEM
|
|||||||
smart_properties
|
smart_properties
|
||||||
bigdecimal (3.1.8)
|
bigdecimal (3.1.8)
|
||||||
bindex (0.8.1)
|
bindex (0.8.1)
|
||||||
bootsnap (1.18.3)
|
bootsnap (1.18.4)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
builder (3.3.0)
|
builder (3.3.0)
|
||||||
bullet (7.1.6)
|
bullet (7.2.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
uniform_notifier (~> 1.11)
|
uniform_notifier (~> 1.11)
|
||||||
camertron-eprun (1.1.1)
|
camertron-eprun (1.1.1)
|
||||||
cancancan (3.5.0)
|
cancancan (3.6.1)
|
||||||
capybara (3.40.0)
|
capybara (3.40.0)
|
||||||
addressable
|
addressable
|
||||||
matrix
|
matrix
|
||||||
@@ -137,7 +133,8 @@ GEM
|
|||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
regexp_parser (>= 1.5, < 3.0)
|
regexp_parser (>= 1.5, < 3.0)
|
||||||
xpath (~> 3.2)
|
xpath (~> 3.2)
|
||||||
childprocess (5.0.0)
|
childprocess (5.1.0)
|
||||||
|
logger (~> 1.5)
|
||||||
chunky_png (1.4.0)
|
chunky_png (1.4.0)
|
||||||
cldr-plurals-runtime-rb (1.1.0)
|
cldr-plurals-runtime-rb (1.1.0)
|
||||||
cmdparse (3.0.7)
|
cmdparse (3.0.7)
|
||||||
@@ -148,12 +145,12 @@ GEM
|
|||||||
bigdecimal
|
bigdecimal
|
||||||
rexml
|
rexml
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
css_parser (1.17.1)
|
css_parser (1.19.0)
|
||||||
addressable
|
addressable
|
||||||
csv (3.3.0)
|
csv (3.3.0)
|
||||||
cuprite (0.15)
|
cuprite (0.15.1)
|
||||||
capybara (~> 3.0)
|
capybara (~> 3.0)
|
||||||
ferrum (~> 0.14.0)
|
ferrum (~> 0.15.0)
|
||||||
date (3.3.4)
|
date (3.3.4)
|
||||||
debug (1.9.2)
|
debug (1.9.2)
|
||||||
irb (~> 1.10)
|
irb (~> 1.10)
|
||||||
@@ -165,7 +162,7 @@ GEM
|
|||||||
railties (>= 4.1.0)
|
railties (>= 4.1.0)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise-two-factor (5.0.0)
|
devise-two-factor (6.0.0)
|
||||||
activesupport (~> 7.0)
|
activesupport (~> 7.0)
|
||||||
devise (~> 4.0)
|
devise (~> 4.0)
|
||||||
railties (~> 7.0)
|
railties (~> 7.0)
|
||||||
@@ -173,26 +170,26 @@ GEM
|
|||||||
diff-lcs (1.5.1)
|
diff-lcs (1.5.1)
|
||||||
digest-crc (0.6.5)
|
digest-crc (0.6.5)
|
||||||
rake (>= 12.0.0, < 14.0.0)
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
docile (1.4.0)
|
docile (1.4.1)
|
||||||
dotenv (3.1.0)
|
dotenv (3.1.4)
|
||||||
drb (2.2.1)
|
drb (2.2.1)
|
||||||
email_typo (0.2.3)
|
email_typo (0.2.3)
|
||||||
erb_lint (0.5.0)
|
erb_lint (0.6.0)
|
||||||
activesupport
|
activesupport
|
||||||
better_html (>= 2.0.1)
|
better_html (>= 2.0.1)
|
||||||
parser (>= 2.7.1.4)
|
parser (>= 2.7.1.4)
|
||||||
rainbow
|
rainbow
|
||||||
rubocop
|
rubocop (>= 1)
|
||||||
smart_properties
|
smart_properties
|
||||||
erubi (1.13.0)
|
erubi (1.13.0)
|
||||||
factory_bot (6.4.6)
|
factory_bot (6.5.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
factory_bot_rails (6.4.3)
|
factory_bot_rails (6.4.3)
|
||||||
factory_bot (~> 6.4)
|
factory_bot (~> 6.4)
|
||||||
railties (>= 5.0.0)
|
railties (>= 5.0.0)
|
||||||
faker (3.3.1)
|
faker (3.4.2)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (1.10.3)
|
faraday (1.10.4)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
faraday-em_synchrony (~> 1.0)
|
faraday-em_synchrony (~> 1.0)
|
||||||
faraday-excon (~> 1.1)
|
faraday-excon (~> 1.1)
|
||||||
@@ -212,87 +209,90 @@ GEM
|
|||||||
faraday-httpclient (1.0.1)
|
faraday-httpclient (1.0.1)
|
||||||
faraday-multipart (1.0.4)
|
faraday-multipart (1.0.4)
|
||||||
multipart-post (~> 2)
|
multipart-post (~> 2)
|
||||||
faraday-net_http (1.0.1)
|
faraday-net_http (1.0.2)
|
||||||
faraday-net_http_persistent (1.2.0)
|
faraday-net_http_persistent (1.2.0)
|
||||||
faraday-patron (1.0.0)
|
faraday-patron (1.0.0)
|
||||||
faraday-rack (1.0.0)
|
faraday-rack (1.0.0)
|
||||||
faraday-retry (1.0.3)
|
faraday-retry (1.0.3)
|
||||||
faraday_middleware (1.2.0)
|
faraday_middleware (1.2.1)
|
||||||
faraday (~> 1.0)
|
faraday (~> 1.0)
|
||||||
ferrum (0.14)
|
ferrum (0.15)
|
||||||
addressable (~> 2.5)
|
addressable (~> 2.5)
|
||||||
concurrent-ruby (~> 1.1)
|
concurrent-ruby (~> 1.1)
|
||||||
webrick (~> 1.7)
|
webrick (~> 1.7)
|
||||||
websocket-driver (>= 0.6, < 0.8)
|
websocket-driver (~> 0.7)
|
||||||
ffi (1.16.3)
|
ffi (1.17.0)
|
||||||
|
ffi (1.17.0-aarch64-linux-gnu)
|
||||||
|
ffi (1.17.0-x86_64-linux-gnu)
|
||||||
geom2d (0.4.1)
|
geom2d (0.4.1)
|
||||||
globalid (1.2.1)
|
globalid (1.2.1)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
google-apis-core (0.14.1)
|
google-apis-core (0.15.1)
|
||||||
addressable (~> 2.5, >= 2.5.1)
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
googleauth (~> 1.9)
|
googleauth (~> 1.9)
|
||||||
httpclient (>= 2.8.1, < 3.a)
|
httpclient (>= 2.8.3, < 3.a)
|
||||||
mini_mime (~> 1.0)
|
mini_mime (~> 1.0)
|
||||||
|
mutex_m
|
||||||
representable (~> 3.0)
|
representable (~> 3.0)
|
||||||
retriable (>= 2.0, < 4.a)
|
retriable (>= 2.0, < 4.a)
|
||||||
rexml
|
google-apis-iamcredentials_v1 (0.21.0)
|
||||||
google-apis-iamcredentials_v1 (0.20.0)
|
google-apis-core (>= 0.15.0, < 2.a)
|
||||||
google-apis-core (>= 0.14.0, < 2.a)
|
google-apis-storage_v1 (0.46.0)
|
||||||
google-apis-storage_v1 (0.37.0)
|
google-apis-core (>= 0.15.0, < 2.a)
|
||||||
google-apis-core (>= 0.14.0, < 2.a)
|
google-cloud-core (1.7.1)
|
||||||
google-cloud-core (1.7.0)
|
|
||||||
google-cloud-env (>= 1.0, < 3.a)
|
google-cloud-env (>= 1.0, < 3.a)
|
||||||
google-cloud-errors (~> 1.0)
|
google-cloud-errors (~> 1.0)
|
||||||
google-cloud-env (2.1.1)
|
google-cloud-env (2.2.1)
|
||||||
faraday (>= 1.0, < 3.a)
|
faraday (>= 1.0, < 3.a)
|
||||||
google-cloud-errors (1.4.0)
|
google-cloud-errors (1.4.0)
|
||||||
google-cloud-storage (1.49.0)
|
google-cloud-storage (1.52.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
digest-crc (~> 0.4)
|
digest-crc (~> 0.4)
|
||||||
google-apis-core (~> 0.13)
|
google-apis-core (~> 0.13)
|
||||||
google-apis-iamcredentials_v1 (~> 0.18)
|
google-apis-iamcredentials_v1 (~> 0.18)
|
||||||
google-apis-storage_v1 (~> 0.33)
|
google-apis-storage_v1 (~> 0.38)
|
||||||
google-cloud-core (~> 1.6)
|
google-cloud-core (~> 1.6)
|
||||||
googleauth (~> 1.9)
|
googleauth (~> 1.9)
|
||||||
mini_mime (~> 1.0)
|
mini_mime (~> 1.0)
|
||||||
googleauth (1.11.0)
|
googleauth (1.11.1)
|
||||||
faraday (>= 1.0, < 3.a)
|
faraday (>= 1.0, < 3.a)
|
||||||
google-cloud-env (~> 2.1)
|
google-cloud-env (~> 2.1)
|
||||||
jwt (>= 1.4, < 3.0)
|
jwt (>= 1.4, < 3.0)
|
||||||
multi_json (~> 1.11)
|
multi_json (~> 1.11)
|
||||||
os (>= 0.9, < 2.0)
|
os (>= 0.9, < 2.0)
|
||||||
signet (>= 0.16, < 2.a)
|
signet (>= 0.16, < 2.a)
|
||||||
hashdiff (1.1.0)
|
hashdiff (1.1.1)
|
||||||
hexapdf (0.42.0)
|
hexapdf (0.47.0)
|
||||||
cmdparse (~> 3.0, >= 3.0.3)
|
cmdparse (~> 3.0, >= 3.0.3)
|
||||||
geom2d (~> 0.4, >= 0.4.1)
|
geom2d (~> 0.4, >= 0.4.1)
|
||||||
openssl (>= 2.2.1)
|
openssl (>= 2.2.1)
|
||||||
htmlentities (4.3.4)
|
htmlentities (4.3.4)
|
||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
i18n (1.14.5)
|
i18n (1.14.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
image_processing (1.12.2)
|
image_processing (1.13.0)
|
||||||
mini_magick (>= 4.9.5, < 5)
|
mini_magick (>= 4.9.5, < 5)
|
||||||
ruby-vips (>= 2.0.17, < 3)
|
ruby-vips (>= 2.0.17, < 3)
|
||||||
io-console (0.7.2)
|
io-console (0.7.2)
|
||||||
irb (1.13.1)
|
irb (1.14.1)
|
||||||
rdoc (>= 4.0.0)
|
rdoc (>= 4.0.0)
|
||||||
reline (>= 0.4.2)
|
reline (>= 0.4.2)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.7.2)
|
json (2.7.2)
|
||||||
jwt (2.8.1)
|
jwt (2.9.3)
|
||||||
base64
|
base64
|
||||||
language_server-protocol (3.17.0.3)
|
language_server-protocol (3.17.0.3)
|
||||||
launchy (3.0.0)
|
launchy (3.0.1)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
childprocess (~> 5.0)
|
childprocess (~> 5.0)
|
||||||
letter_opener (1.10.0)
|
letter_opener (1.10.0)
|
||||||
launchy (>= 2.2, < 4)
|
launchy (>= 2.2, < 4)
|
||||||
letter_opener_web (2.0.0)
|
letter_opener_web (3.0.0)
|
||||||
actionmailer (>= 5.2)
|
actionmailer (>= 6.1)
|
||||||
letter_opener (~> 1.7)
|
letter_opener (~> 1.9)
|
||||||
railties (>= 5.2)
|
railties (>= 6.1)
|
||||||
rexml
|
rexml
|
||||||
|
logger (1.6.1)
|
||||||
lograge (0.14.0)
|
lograge (0.14.0)
|
||||||
actionpack (>= 4)
|
actionpack (>= 4)
|
||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
@@ -309,26 +309,27 @@ GEM
|
|||||||
marcel (1.0.4)
|
marcel (1.0.4)
|
||||||
matrix (0.4.2)
|
matrix (0.4.2)
|
||||||
method_source (1.1.0)
|
method_source (1.1.0)
|
||||||
mini_magick (4.12.0)
|
mini_magick (4.13.2)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.7)
|
mini_portile2 (2.8.7)
|
||||||
minitest (5.24.1)
|
minitest (5.25.1)
|
||||||
msgpack (1.7.2)
|
msgpack (1.7.3)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.4.0)
|
multipart-post (2.4.1)
|
||||||
mutex_m (0.2.0)
|
mutex_m (0.2.0)
|
||||||
mysql2 (0.5.6)
|
mysql2 (0.5.6)
|
||||||
net-http-persistent (4.0.2)
|
net-http-persistent (4.0.4)
|
||||||
connection_pool (~> 2.2)
|
connection_pool (~> 2.2)
|
||||||
net-imap (0.4.14)
|
net-imap (0.4.16)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
|
net-protocol
|
||||||
net-protocol (0.2.2)
|
net-protocol (0.2.2)
|
||||||
timeout
|
timeout
|
||||||
net-smtp (0.4.0)
|
net-smtp (0.5.0)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.1)
|
nio4r (2.7.3)
|
||||||
nokogiri (1.16.7)
|
nokogiri (1.16.7)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
@@ -336,21 +337,23 @@ GEM
|
|||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.16.7-x86_64-linux)
|
nokogiri (1.16.7-x86_64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oj (3.16.3)
|
oj (3.16.6)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
|
ostruct (>= 0.2)
|
||||||
openssl (3.2.0)
|
openssl (3.2.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
os (1.1.4)
|
os (1.1.4)
|
||||||
|
ostruct (0.6.0)
|
||||||
package_json (0.1.0)
|
package_json (0.1.0)
|
||||||
pagy (8.1.2)
|
pagy (9.1.0)
|
||||||
parallel (1.25.1)
|
parallel (1.26.3)
|
||||||
parser (3.3.4.0)
|
parser (3.3.5.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
pg (1.5.6)
|
pg (1.5.8)
|
||||||
premailer (1.23.0)
|
premailer (1.27.0)
|
||||||
addressable
|
addressable
|
||||||
css_parser (>= 1.12.0)
|
css_parser (>= 1.19.0)
|
||||||
htmlentities (>= 4.0.0)
|
htmlentities (>= 4.0.0)
|
||||||
premailer-rails (1.12.0)
|
premailer-rails (1.12.0)
|
||||||
actionmailer (>= 3)
|
actionmailer (>= 3)
|
||||||
@@ -361,12 +364,12 @@ GEM
|
|||||||
pry (0.14.2)
|
pry (0.14.2)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
method_source (~> 1.0)
|
method_source (~> 1.0)
|
||||||
pry-rails (0.3.9)
|
pry-rails (0.3.11)
|
||||||
pry (>= 0.10.4)
|
pry (>= 0.13.0)
|
||||||
psych (5.1.2)
|
psych (5.1.2)
|
||||||
stringio
|
stringio
|
||||||
public_suffix (5.0.5)
|
public_suffix (6.0.1)
|
||||||
puma (6.4.2)
|
puma (6.4.3)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.8.1)
|
racc (1.8.1)
|
||||||
rack (3.1.7)
|
rack (3.1.7)
|
||||||
@@ -379,20 +382,20 @@ GEM
|
|||||||
rackup (2.1.0)
|
rackup (2.1.0)
|
||||||
rack (>= 3)
|
rack (>= 3)
|
||||||
webrick (~> 1.8)
|
webrick (~> 1.8)
|
||||||
rails (7.1.3.4)
|
rails (7.2.1)
|
||||||
actioncable (= 7.1.3.4)
|
actioncable (= 7.2.1)
|
||||||
actionmailbox (= 7.1.3.4)
|
actionmailbox (= 7.2.1)
|
||||||
actionmailer (= 7.1.3.4)
|
actionmailer (= 7.2.1)
|
||||||
actionpack (= 7.1.3.4)
|
actionpack (= 7.2.1)
|
||||||
actiontext (= 7.1.3.4)
|
actiontext (= 7.2.1)
|
||||||
actionview (= 7.1.3.4)
|
actionview (= 7.2.1)
|
||||||
activejob (= 7.1.3.4)
|
activejob (= 7.2.1)
|
||||||
activemodel (= 7.1.3.4)
|
activemodel (= 7.2.1)
|
||||||
activerecord (= 7.1.3.4)
|
activerecord (= 7.2.1)
|
||||||
activestorage (= 7.1.3.4)
|
activestorage (= 7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 7.1.3.4)
|
railties (= 7.2.1)
|
||||||
rails-dom-testing (2.2.0)
|
rails-dom-testing (2.2.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
minitest
|
minitest
|
||||||
@@ -407,100 +410,101 @@ GEM
|
|||||||
actionview (> 3.1)
|
actionview (> 3.1)
|
||||||
activesupport (> 3.1)
|
activesupport (> 3.1)
|
||||||
railties (> 3.1)
|
railties (> 3.1)
|
||||||
railties (7.1.3.4)
|
railties (7.2.1)
|
||||||
actionpack (= 7.1.3.4)
|
actionpack (= 7.2.1)
|
||||||
activesupport (= 7.1.3.4)
|
activesupport (= 7.2.1)
|
||||||
irb
|
irb (~> 1.13)
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
thor (~> 1.0, >= 1.2.2)
|
thor (~> 1.0, >= 1.2.2)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.2.1)
|
rake (13.2.1)
|
||||||
rdoc (6.6.3.1)
|
rdoc (6.7.0)
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
redis-client (0.22.2)
|
redis-client (0.22.2)
|
||||||
connection_pool
|
connection_pool
|
||||||
regexp_parser (2.9.2)
|
regexp_parser (2.9.2)
|
||||||
reline (0.5.7)
|
reline (0.5.10)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
representable (3.2.0)
|
representable (3.2.0)
|
||||||
declarative (< 0.1.0)
|
declarative (< 0.1.0)
|
||||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||||
uber (< 0.2.0)
|
uber (< 0.2.0)
|
||||||
request_store (1.6.0)
|
request_store (1.7.0)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.1.1)
|
responders (3.1.1)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
retriable (3.1.2)
|
retriable (3.1.2)
|
||||||
rexml (3.3.3)
|
rexml (3.3.8)
|
||||||
strscan
|
|
||||||
rotp (6.3.0)
|
rotp (6.3.0)
|
||||||
rqrcode (2.2.0)
|
rqrcode (2.2.0)
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
rqrcode_core (~> 1.0)
|
rqrcode_core (~> 1.0)
|
||||||
rqrcode_core (1.2.0)
|
rqrcode_core (1.2.0)
|
||||||
rspec-core (3.13.0)
|
rspec-core (3.13.1)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-expectations (3.13.0)
|
rspec-expectations (3.13.3)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-mocks (3.13.0)
|
rspec-mocks (3.13.2)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-rails (6.1.2)
|
rspec-rails (7.0.1)
|
||||||
actionpack (>= 6.1)
|
actionpack (>= 7.0)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 7.0)
|
||||||
railties (>= 6.1)
|
railties (>= 7.0)
|
||||||
rspec-core (~> 3.13)
|
rspec-core (~> 3.13)
|
||||||
rspec-expectations (~> 3.13)
|
rspec-expectations (~> 3.13)
|
||||||
rspec-mocks (~> 3.13)
|
rspec-mocks (~> 3.13)
|
||||||
rspec-support (~> 3.13)
|
rspec-support (~> 3.13)
|
||||||
rspec-support (3.13.1)
|
rspec-support (3.13.1)
|
||||||
rubocop (1.65.0)
|
rubocop (1.66.1)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (>= 3.17.0)
|
language_server-protocol (>= 3.17.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.3.0.2)
|
parser (>= 3.3.0.2)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 2.4, < 3.0)
|
regexp_parser (>= 2.4, < 3.0)
|
||||||
rexml (>= 3.2.5, < 4.0)
|
rubocop-ast (>= 1.32.2, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 3.0)
|
unicode-display_width (>= 2.4.0, < 3.0)
|
||||||
rubocop-ast (1.31.3)
|
rubocop-ast (1.32.3)
|
||||||
parser (>= 3.3.1.0)
|
parser (>= 3.3.1.0)
|
||||||
rubocop-performance (1.21.0)
|
rubocop-performance (1.22.1)
|
||||||
rubocop (>= 1.48.1, < 2.0)
|
rubocop (>= 1.48.1, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop-ast (>= 1.31.1, < 2.0)
|
||||||
rubocop-rails (2.24.1)
|
rubocop-rails (2.26.2)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.33.0, < 2.0)
|
rubocop (>= 1.52.0, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop-ast (>= 1.31.1, < 2.0)
|
||||||
rubocop-rspec (3.0.3)
|
rubocop-rspec (3.1.0)
|
||||||
rubocop (~> 1.61)
|
rubocop (~> 1.61)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-vips (2.2.1)
|
ruby-vips (2.2.2)
|
||||||
ffi (~> 1.12)
|
ffi (~> 1.12)
|
||||||
|
logger
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
rubyXL (3.4.27)
|
rubyXL (3.4.27)
|
||||||
nokogiri (>= 1.10.8)
|
nokogiri (>= 1.10.8)
|
||||||
rubyzip (>= 1.3.0)
|
rubyzip (>= 1.3.0)
|
||||||
rubyzip (2.3.2)
|
rubyzip (2.3.2)
|
||||||
|
securerandom (0.3.1)
|
||||||
semantic_range (3.0.0)
|
semantic_range (3.0.0)
|
||||||
shakapacker (8.0.0)
|
shakapacker (8.0.2)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
package_json
|
package_json
|
||||||
rack-proxy (>= 0.6.1)
|
rack-proxy (>= 0.6.1)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
semantic_range (>= 2.3.0)
|
semantic_range (>= 2.3.0)
|
||||||
sidekiq (7.2.4)
|
sidekiq (7.3.2)
|
||||||
concurrent-ruby (< 2)
|
concurrent-ruby (< 2)
|
||||||
connection_pool (>= 2.3.0)
|
connection_pool (>= 2.3.0)
|
||||||
|
logger
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4)
|
||||||
redis-client (>= 0.19.0)
|
redis-client (>= 0.22.2)
|
||||||
signet (0.19.0)
|
signet (0.19.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
faraday (>= 0.17.5, < 3.a)
|
faraday (>= 0.17.5, < 3.a)
|
||||||
@@ -510,33 +514,34 @@ GEM
|
|||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
simplecov-html (~> 0.11)
|
simplecov-html (~> 0.11)
|
||||||
simplecov_json_formatter (~> 0.1)
|
simplecov_json_formatter (~> 0.1)
|
||||||
simplecov-html (0.12.3)
|
simplecov-html (0.13.1)
|
||||||
simplecov_json_formatter (0.1.4)
|
simplecov_json_formatter (0.1.4)
|
||||||
smart_properties (1.17.0)
|
smart_properties (1.17.0)
|
||||||
sqlite3 (1.7.3)
|
sqlite3 (2.1.0)
|
||||||
mini_portile2 (~> 2.8.0)
|
mini_portile2 (~> 2.8.0)
|
||||||
stringio (3.1.0)
|
sqlite3 (2.1.0-aarch64-linux-gnu)
|
||||||
|
sqlite3 (2.1.0-x86_64-linux-gnu)
|
||||||
|
stringio (3.1.1)
|
||||||
strip_attributes (1.13.0)
|
strip_attributes (1.13.0)
|
||||||
activemodel (>= 3.0, < 8.0)
|
activemodel (>= 3.0, < 8.0)
|
||||||
strscan (3.1.0)
|
thor (1.3.2)
|
||||||
thor (1.3.1)
|
|
||||||
timeout (0.4.1)
|
timeout (0.4.1)
|
||||||
trailblazer-option (0.1.2)
|
trailblazer-option (0.1.2)
|
||||||
turbo-rails (2.0.5)
|
turbo-rails (2.0.10)
|
||||||
actionpack (>= 6.0.0)
|
actionpack (>= 6.0.0)
|
||||||
activejob (>= 6.0.0)
|
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
twitter_cldr (6.12.0)
|
twitter_cldr (6.12.1)
|
||||||
camertron-eprun
|
camertron-eprun
|
||||||
cldr-plurals-runtime-rb (~> 1.1)
|
cldr-plurals-runtime-rb (~> 1.1)
|
||||||
tzinfo
|
tzinfo
|
||||||
tzinfo (2.0.6)
|
tzinfo (2.0.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
tzinfo-data (1.2024.1)
|
tzinfo-data (1.2024.2)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
uber (0.1.0)
|
uber (0.1.0)
|
||||||
unicode-display_width (2.5.0)
|
unicode-display_width (2.6.0)
|
||||||
uniform_notifier (1.16.0)
|
uniform_notifier (1.16.0)
|
||||||
|
useragent (0.16.10)
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.9)
|
rack (>= 2.0.9)
|
||||||
web-console (4.2.1)
|
web-console (4.2.1)
|
||||||
@@ -544,17 +549,17 @@ GEM
|
|||||||
activemodel (>= 6.0.0)
|
activemodel (>= 6.0.0)
|
||||||
bindex (>= 0.4.0)
|
bindex (>= 0.4.0)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
webmock (3.23.0)
|
webmock (3.24.0)
|
||||||
addressable (>= 2.8.0)
|
addressable (>= 2.8.0)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff (>= 0.4.0, < 2.0.0)
|
hashdiff (>= 0.4.0, < 2.0.0)
|
||||||
webrick (1.8.1)
|
webrick (1.8.2)
|
||||||
websocket-driver (0.7.6)
|
websocket-driver (0.7.6)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
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.6.14)
|
zeitwerk (2.6.18)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
aarch64-linux
|
aarch64-linux
|
||||||
@@ -591,7 +596,6 @@ DEPENDENCIES
|
|||||||
letter_opener_web
|
letter_opener_web
|
||||||
lograge
|
lograge
|
||||||
mysql2
|
mysql2
|
||||||
net-smtp (= 0.4.0)
|
|
||||||
oj
|
oj
|
||||||
pagy
|
pagy
|
||||||
pg
|
pg
|
||||||
@@ -624,7 +628,7 @@ DEPENDENCIES
|
|||||||
webmock
|
webmock
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 3.3.3p89
|
ruby 3.3.4p94
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.5.3
|
2.5.3
|
||||||
@@ -42,7 +42,7 @@ DocuSeal is an open source platform that provides secure and efficient digital d
|
|||||||
- PDF signature verification
|
- PDF signature verification
|
||||||
- Users management
|
- Users management
|
||||||
- Mobile-optimized
|
- Mobile-optimized
|
||||||
- Signing available in 13 languages
|
- 6 UI languages with signing available in 13 languages
|
||||||
- API and Webhooks for integrations
|
- API and Webhooks for integrations
|
||||||
- Easy to deploy in minutes
|
- Easy to deploy in minutes
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class AccountConfigsController < ApplicationController
|
|||||||
AccountConfig::FORCE_SSO_AUTH_KEY,
|
AccountConfig::FORCE_SSO_AUTH_KEY,
|
||||||
AccountConfig::FLATTEN_RESULT_PDF_KEY,
|
AccountConfig::FLATTEN_RESULT_PDF_KEY,
|
||||||
AccountConfig::WITH_SIGNATURE_ID,
|
AccountConfig::WITH_SIGNATURE_ID,
|
||||||
|
AccountConfig::COMBINE_PDF_RESULT_KEY,
|
||||||
AccountConfig::REQUIRE_SIGNING_REASON_KEY
|
AccountConfig::REQUIRE_SIGNING_REASON_KEY
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ class AccountsController < ApplicationController
|
|||||||
LOCALE_OPTIONS = {
|
LOCALE_OPTIONS = {
|
||||||
'en-US' => 'English (United States)',
|
'en-US' => 'English (United States)',
|
||||||
'en-GB' => 'English (United Kingdom)',
|
'en-GB' => 'English (United Kingdom)',
|
||||||
'fr-FR' => 'French (France)',
|
'fr-FR' => 'Français',
|
||||||
'es-ES' => 'Spanish (Spain)',
|
'es-ES' => 'Español',
|
||||||
'pt-PT' => 'Portuguese (Portugal)',
|
'pt-PT' => 'Português',
|
||||||
'de-DE' => 'German (Germany)',
|
'de-DE' => 'Deutsch',
|
||||||
'it-IT' => 'Italian (Italy)'
|
'it-IT' => 'Italiano'
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
before_action :load_account
|
before_action :load_account
|
||||||
@@ -19,21 +19,25 @@ class AccountsController < ApplicationController
|
|||||||
def update
|
def update
|
||||||
current_account.update!(account_params)
|
current_account.update!(account_params)
|
||||||
|
|
||||||
@encrypted_config = EncryptedConfig.find_or_initialize_by(account: current_account,
|
unless Docuseal.multitenant?
|
||||||
key: EncryptedConfig::APP_URL_KEY)
|
@encrypted_config = EncryptedConfig.find_or_initialize_by(account: current_account,
|
||||||
@encrypted_config.assign_attributes(app_url_params)
|
key: EncryptedConfig::APP_URL_KEY)
|
||||||
|
@encrypted_config.assign_attributes(app_url_params)
|
||||||
|
|
||||||
unless URI.parse(@encrypted_config.value.to_s).class.in?([URI::HTTP, URI::HTTPS])
|
unless URI.parse(@encrypted_config.value.to_s).class.in?([URI::HTTP, URI::HTTPS])
|
||||||
@encrypted_config.errors.add(:value, 'should be a valid URL')
|
@encrypted_config.errors.add(:value, I18n.t('should_be_a_valid_url'))
|
||||||
|
|
||||||
return render :show, status: :unprocessable_entity
|
return render :show, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
|
||||||
|
@encrypted_config.save!
|
||||||
|
|
||||||
|
Docuseal.refresh_default_url_options!
|
||||||
end
|
end
|
||||||
|
|
||||||
@encrypted_config.save!
|
with_locale do
|
||||||
|
redirect_to settings_account_path, notice: I18n.t('account_information_has_been_updated')
|
||||||
Docuseal.refresh_default_url_options!
|
end
|
||||||
|
|
||||||
redirect_to settings_account_path, notice: 'Account information has been updated'
|
|
||||||
rescue ActiveRecord::RecordInvalid
|
rescue ActiveRecord::RecordInvalid
|
||||||
render :show, status: :unprocessable_entity
|
render :show, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
@@ -43,11 +47,12 @@ class AccountsController < ApplicationController
|
|||||||
|
|
||||||
true_user.update!(locked_at: Time.current)
|
true_user.update!(locked_at: Time.current)
|
||||||
|
|
||||||
|
# rubocop:disable Layout/LineLength
|
||||||
render turbo_stream: turbo_stream.replace(
|
render turbo_stream: turbo_stream.replace(
|
||||||
:account_delete_button,
|
:account_delete_button,
|
||||||
html: helpers.tag.p('Your account removal request will be processed within 2 weeks. ' \
|
html: helpers.tag.p(I18n.t('your_account_removal_request_will_be_processed_within_2_weeks_please_contact_us_if_you_want_to_keep_your_account'))
|
||||||
'Please contact us if you want to keep your account.')
|
|
||||||
)
|
)
|
||||||
|
# rubocop:enable Layout/LineLength
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -38,12 +38,12 @@ module Api
|
|||||||
private
|
private
|
||||||
|
|
||||||
def authorization_check!(blob)
|
def authorization_check!(blob)
|
||||||
is_authorized =
|
attachment = blob.attachments.take
|
||||||
blob.attachments.all? do |a|
|
|
||||||
a.name.in?(%w[logo preview_images]) ||
|
is_authorized = attachment.name.in?(%w[logo preview_images]) ||
|
||||||
(current_user && a.record.account.id == current_user.account_id) ||
|
(current_user && attachment.record.account.id == current_user.account_id) ||
|
||||||
!a.record.account.account_configs.find_or_initialize_by(key: AccountConfig::DOWNLOAD_LINKS_AUTH_KEY).value
|
!attachment.record.account.account_configs
|
||||||
end
|
.find_or_initialize_by(key: AccountConfig::DOWNLOAD_LINKS_AUTH_KEY).value
|
||||||
|
|
||||||
return if is_authorized
|
return if is_authorized
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ module Api
|
|||||||
params[:before] = Time.zone.at(params[:before].to_i) if params[:before].present?
|
params[:before] = Time.zone.at(params[:before].to_i) if params[:before].present?
|
||||||
|
|
||||||
submitters = paginate(
|
submitters = paginate(
|
||||||
submitters.preload(template: :folder, submission: [:submitters, { audit_trail_attachment: :blob }],
|
submitters.preload(template: :folder, submission: [:submitters, { audit_trail_attachment: :blob,
|
||||||
|
combined_document_attachment: :blob }],
|
||||||
documents_attachments: :blob, attachments_attachments: :blob),
|
documents_attachments: :blob, attachments_attachments: :blob),
|
||||||
field: :completed_at
|
field: :completed_at
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,10 +19,14 @@ module Api
|
|||||||
|
|
||||||
submissions = paginate(submissions.preload(:created_by_user, :submitters,
|
submissions = paginate(submissions.preload(:created_by_user, :submitters,
|
||||||
template: :folder,
|
template: :folder,
|
||||||
|
combined_document_attachment: :blob,
|
||||||
audit_trail_attachment: :blob))
|
audit_trail_attachment: :blob))
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
data: submissions.as_json(Submissions::SerializeForApi::SERIALIZE_PARAMS),
|
data: submissions.map do |s|
|
||||||
|
Submissions::SerializeForApi.call(s, s.submitters, params,
|
||||||
|
with_events: false, with_documents: false, with_values: false)
|
||||||
|
end,
|
||||||
pagination: {
|
pagination: {
|
||||||
count: submissions.size,
|
count: submissions.size,
|
||||||
next: submissions.last&.id,
|
next: submissions.last&.id,
|
||||||
@@ -76,7 +80,7 @@ module Api
|
|||||||
end
|
end
|
||||||
|
|
||||||
render json: build_create_json(submissions)
|
render json: build_create_json(submissions)
|
||||||
rescue Submitters::NormalizeValues::BaseError => e
|
rescue Submitters::NormalizeValues::BaseError, DownloadUtils::UnableToDownload => e
|
||||||
Rollbar.warning(e) if defined?(Rollbar)
|
Rollbar.warning(e) if defined?(Rollbar)
|
||||||
|
|
||||||
render json: { error: e.message }, status: :unprocessable_entity
|
render json: { error: e.message }, status: :unprocessable_entity
|
||||||
@@ -154,7 +158,7 @@ module Api
|
|||||||
:completed, :phone, :application_key, :external_id, :reply_to, :go_to_last,
|
:completed, :phone, :application_key, :external_id, :reply_to, :go_to_last,
|
||||||
{ metadata: {}, values: {}, readonly_fields: [], message: %i[subject body],
|
{ metadata: {}, values: {}, readonly_fields: [], message: %i[subject body],
|
||||||
fields: [:name, :uuid, :default_value, :value, :title, :description,
|
fields: [:name, :uuid, :default_value, :value, :title, :description,
|
||||||
:readonly, :redacted, :validation_pattern, :invalid_message,
|
:readonly, :validation_pattern, :invalid_message,
|
||||||
{ default_value: [], value: [], preferences: {} }] }]]
|
{ default_value: [], value: [], preferences: {} }] }]]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ module Api
|
|||||||
with_urls: true,
|
with_urls: true,
|
||||||
with_events: false,
|
with_events: false,
|
||||||
params:)
|
params:)
|
||||||
|
rescue Submitters::NormalizeValues::BaseError, DownloadUtils::UnableToDownload => e
|
||||||
|
Rollbar.warning(e) if defined?(Rollbar)
|
||||||
|
|
||||||
|
render json: { error: e.message }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|
||||||
def submitter_params
|
def submitter_params
|
||||||
@@ -87,7 +91,7 @@ module Api
|
|||||||
:completed, :phone, :application_key, :external_id, :go_to_last,
|
:completed, :phone, :application_key, :external_id, :go_to_last,
|
||||||
{ metadata: {}, values: {}, readonly_fields: [], message: %i[subject body],
|
{ metadata: {}, values: {}, readonly_fields: [], message: %i[subject body],
|
||||||
fields: [[:name, :uuid, :default_value, :value,
|
fields: [[:name, :uuid, :default_value, :value,
|
||||||
:readonly, :redacted, :validation_pattern, :invalid_message,
|
:readonly, :validation_pattern, :invalid_message,
|
||||||
{ default_value: [], value: [], preferences: {} }]] }
|
{ default_value: [], value: [], preferences: {} }]] }
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ module Api
|
|||||||
|
|
||||||
preview_image_attachments =
|
preview_image_attachments =
|
||||||
ActiveStorage::Attachment.joins(:blob)
|
ActiveStorage::Attachment.joins(:blob)
|
||||||
.where(blob: { filename: '0.jpg' })
|
.where(blob: { filename: ['0.png', '0.jpg'] })
|
||||||
.where(record_id: schema_documents.map(&:id),
|
.where(record_id: schema_documents.map(&:id),
|
||||||
record_type: 'ActiveStorage::Attachment',
|
record_type: 'ActiveStorage::Attachment',
|
||||||
name: :preview_images)
|
name: :preview_images)
|
||||||
@@ -97,7 +97,7 @@ module Api
|
|||||||
:name,
|
:name,
|
||||||
:external_id,
|
:external_id,
|
||||||
{
|
{
|
||||||
submitters: [%i[name uuid]],
|
submitters: [%i[name uuid is_requester invite_by_uuid linked_to_uuid email]],
|
||||||
fields: [[:uuid, :submitter_uuid, :name, :type,
|
fields: [[:uuid, :submitter_uuid, :name, :type,
|
||||||
:required, :readonly, :default_value,
|
:required, :readonly, :default_value,
|
||||||
:title, :description,
|
:title, :description,
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ class ApiSettingsController < ApplicationController
|
|||||||
|
|
||||||
current_user.access_token.save!
|
current_user.access_token.save!
|
||||||
|
|
||||||
redirect_back(fallback_location: settings_api_index_path, notice: 'API token as been updated.')
|
redirect_back(fallback_location: settings_api_index_path, notice: I18n.t('api_token_has_been_updated'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -8,6 +8,7 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
check_authorization unless: :devise_controller?
|
check_authorization unless: :devise_controller?
|
||||||
|
|
||||||
|
around_action :with_locale
|
||||||
before_action :sign_in_for_demo, if: -> { Docuseal.demo? }
|
before_action :sign_in_for_demo, if: -> { Docuseal.demo? }
|
||||||
before_action :maybe_redirect_to_setup, unless: :signed_in?
|
before_action :maybe_redirect_to_setup, unless: :signed_in?
|
||||||
before_action :authenticate_user!, unless: :devise_controller?
|
before_action :authenticate_user!, unless: :devise_controller?
|
||||||
@@ -51,7 +52,18 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def with_locale(&)
|
||||||
|
return yield unless current_account
|
||||||
|
|
||||||
|
locale = params[:lang].presence if Rails.env.development?
|
||||||
|
locale ||= current_account.locale
|
||||||
|
|
||||||
|
I18n.with_locale(locale, &)
|
||||||
|
end
|
||||||
|
|
||||||
def with_browser_locale(&)
|
def with_browser_locale(&)
|
||||||
|
return yield if I18n.locale != :'en-US' && I18n.locale != :en
|
||||||
|
|
||||||
locale = params[:lang].presence
|
locale = params[:lang].presence
|
||||||
locale ||= request.env['HTTP_ACCEPT_LANGUAGE'].to_s[BROWSER_LOCALE_REGEXP].to_s
|
locale ||= request.env['HTTP_ACCEPT_LANGUAGE'].to_s[BROWSER_LOCALE_REGEXP].to_s
|
||||||
|
|
||||||
@@ -79,7 +91,8 @@ class ApplicationController < ActionController::Base
|
|||||||
redirect_to setup_index_path unless User.exists?
|
redirect_to setup_index_path unless User.exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
def button_title(title: 'Submit', disabled_with: 'Submitting', title_class: '', icon: nil, icon_disabled: nil)
|
def button_title(title: I18n.t('submit'), disabled_with: I18n.t('submitting'), title_class: '', icon: nil,
|
||||||
|
icon_disabled: nil)
|
||||||
render_to_string(partial: 'shared/button_title',
|
render_to_string(partial: 'shared/button_title',
|
||||||
locals: { title:, disabled_with:, title_class:, icon:, icon_disabled: })
|
locals: { title:, disabled_with:, title_class:, icon:, icon_disabled: })
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class DashboardController < ApplicationController
|
|||||||
account_id: current_user.account_id,
|
account_id: current_user.account_id,
|
||||||
key: AccountConfig::FORCE_MFA)
|
key: AccountConfig::FORCE_MFA)
|
||||||
|
|
||||||
redirect_to mfa_setup_path, notice: 'Setup 2FA to continue'
|
redirect_to mfa_setup_path, notice: I18n.t('setup_2fa_to_continue')
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_render_landing
|
def maybe_render_landing
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class EmailSmtpSettingsController < ApplicationController
|
|||||||
if @encrypted_config.update(email_configs)
|
if @encrypted_config.update(email_configs)
|
||||||
SettingsMailer.smtp_successful_setup(@encrypted_config.value['from_email']).deliver_now!
|
SettingsMailer.smtp_successful_setup(@encrypted_config.value['from_email']).deliver_now!
|
||||||
|
|
||||||
redirect_to settings_email_index_path, notice: 'Changes have been saved'
|
redirect_to settings_email_index_path, notice: I18n.t('changes_have_been_saved')
|
||||||
else
|
else
|
||||||
render :index, status: :unprocessable_entity
|
render :index, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ class EsignSettingsController < ApplicationController
|
|||||||
default_pkcs = GenerateCertificate.load_pkcs(cert_data) if cert_data['cert'].present?
|
default_pkcs = GenerateCertificate.load_pkcs(cert_data) if cert_data['cert'].present?
|
||||||
|
|
||||||
custom_pkcs_list = (cert_data['custom'] || []).map do |e|
|
custom_pkcs_list = (cert_data['custom'] || []).map do |e|
|
||||||
{ 'pkcs' => OpenSSL::PKCS12.new(Base64.urlsafe_decode64(e['data']), e['password'].to_s),
|
pkcs = e['data'].present? ? OpenSSL::PKCS12.new(Base64.urlsafe_decode64(e['data']), e['password'].to_s) : nil
|
||||||
'name' => e['name'],
|
|
||||||
'status' => e['status'] }
|
{ 'pkcs' => pkcs, 'name' => e['name'], 'status' => e['status'] }
|
||||||
end
|
end
|
||||||
|
|
||||||
@pkcs_list = [
|
@pkcs_list = [
|
||||||
@@ -48,7 +48,7 @@ class EsignSettingsController < ApplicationController
|
|||||||
if (@encrypted_config.value && @encrypted_config.value['custom']&.any? { |e| e['name'] == @cert_record.name }) ||
|
if (@encrypted_config.value && @encrypted_config.value['custom']&.any? { |e| e['name'] == @cert_record.name }) ||
|
||||||
@cert_record.name == DEFAULT_CERT_NAME
|
@cert_record.name == DEFAULT_CERT_NAME
|
||||||
|
|
||||||
@cert_record.errors.add(:name, 'already exists')
|
@cert_record.errors.add(:name, I18n.t('already_exists'))
|
||||||
|
|
||||||
return render turbo_stream: turbo_stream.replace(:modal, template: 'esign_settings/new'),
|
return render turbo_stream: turbo_stream.replace(:modal, template: 'esign_settings/new'),
|
||||||
status: :unprocessable_entity
|
status: :unprocessable_entity
|
||||||
@@ -56,7 +56,7 @@ class EsignSettingsController < ApplicationController
|
|||||||
|
|
||||||
save_new_cert!(@encrypted_config, @cert_record)
|
save_new_cert!(@encrypted_config, @cert_record)
|
||||||
|
|
||||||
redirect_to settings_esign_path, notice: 'Certificate has been successfully added!'
|
redirect_to settings_esign_path, notice: I18n.t('certificate_has_been_successfully_added')
|
||||||
rescue OpenSSL::PKCS12::PKCS12Error => e
|
rescue OpenSSL::PKCS12::PKCS12Error => e
|
||||||
Rollbar.error(e) if defined?(Rollbar)
|
Rollbar.error(e) if defined?(Rollbar)
|
||||||
|
|
||||||
@@ -66,14 +66,20 @@ class EsignSettingsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@encrypted_config.value['custom'].each { |e| e['status'] = 'validate' }
|
@encrypted_config.value['custom'].to_a.each { |e| e['status'] = 'validate' }
|
||||||
|
|
||||||
custom_cert_data = @encrypted_config.value['custom'].find { |e| e['name'] == params[:name] }
|
custom_cert_data = @encrypted_config.value['custom'].to_a.find { |e| e['name'] == params[:name] }
|
||||||
custom_cert_data['status'] = 'default' if custom_cert_data
|
|
||||||
|
if custom_cert_data
|
||||||
|
custom_cert_data['status'] = 'default'
|
||||||
|
elsif params[:name] == Docuseal::AATL_CERT_NAME
|
||||||
|
@encrypted_config.value['custom'] ||= []
|
||||||
|
@encrypted_config.value['custom'] << { 'name' => params[:name], 'status' => 'default' }
|
||||||
|
end
|
||||||
|
|
||||||
@encrypted_config.save!
|
@encrypted_config.save!
|
||||||
|
|
||||||
redirect_to settings_esign_path, notice: 'Default certificate has been selected'
|
redirect_to settings_esign_path, notice: I18n.t('default_certificate_has_been_selected')
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@@ -81,7 +87,7 @@ class EsignSettingsController < ApplicationController
|
|||||||
|
|
||||||
@encrypted_config.save!
|
@encrypted_config.save!
|
||||||
|
|
||||||
redirect_to settings_esign_path, notice: 'Certificate has been removed'
|
redirect_to settings_esign_path, notice: I18n.t('certificate_has_been_removed')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ class MfaSetupController < ApplicationController
|
|||||||
current_user.otp_required_for_login = true
|
current_user.otp_required_for_login = true
|
||||||
current_user.save!
|
current_user.save!
|
||||||
|
|
||||||
redirect_to settings_profile_index_path, notice: '2FA has been configured'
|
redirect_to settings_profile_index_path, notice: I18n.t('2fa_has_been_configured')
|
||||||
else
|
else
|
||||||
@provision_url = current_user.otp_provisioning_uri(current_user.email, issuer: Docuseal.product_name)
|
@provision_url = current_user.otp_provisioning_uri(current_user.email, issuer: Docuseal.product_name)
|
||||||
|
|
||||||
@error_message = 'Code is invalid'
|
@error_message = I18n.t('code_is_invalid')
|
||||||
|
|
||||||
render turbo_stream: turbo_stream.replace(:mfa_form, partial: 'mfa_setup/form'), status: :unprocessable_entity
|
render turbo_stream: turbo_stream.replace(:mfa_form, partial: 'mfa_setup/form'), status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
@@ -32,9 +32,9 @@ class MfaSetupController < ApplicationController
|
|||||||
if current_user.validate_and_consume_otp!(params[:otp_attempt])
|
if current_user.validate_and_consume_otp!(params[:otp_attempt])
|
||||||
current_user.update!(otp_required_for_login: false, otp_secret: nil)
|
current_user.update!(otp_required_for_login: false, otp_secret: nil)
|
||||||
|
|
||||||
redirect_to settings_profile_index_path, notice: '2FA has been removed'
|
redirect_to settings_profile_index_path, notice: I18n.t('2fa_has_been_removed')
|
||||||
else
|
else
|
||||||
@error_message = 'Code is invalid'
|
@error_message = I18n.t('code_is_invalid')
|
||||||
|
|
||||||
render turbo_stream: turbo_stream.replace(:modal, template: 'mfa_setup/edit'), status: :unprocessable_entity
|
render turbo_stream: turbo_stream.replace(:modal, template: 'mfa_setup/edit'), status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
@@ -43,7 +43,7 @@ class MfaSetupController < ApplicationController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_provision_url
|
def set_provision_url
|
||||||
return redirect_to root_path, alert: '2FA has been set up already' if current_user.otp_required_for_login
|
return redirect_to root_path, alert: I18n.t('2fa_has_been_set_up_already') if current_user.otp_required_for_login
|
||||||
|
|
||||||
current_user.otp_secret ||= User.generate_otp_secret
|
current_user.otp_secret ||= User.generate_otp_secret
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ class NotificationsSettingsController < ApplicationController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
if @account_config.value.present? ? @account_config.save : @account_config.delete
|
if @account_config.value.present? ? @account_config.save : @account_config.delete
|
||||||
redirect_back fallback_location: settings_notifications_path, notice: 'Changes have been saved'
|
redirect_back fallback_location: settings_notifications_path, notice: I18n.t('changes_have_been_saved')
|
||||||
else
|
else
|
||||||
redirect_back fallback_location: settings_notifications_path, alert: 'Unable to save'
|
redirect_back fallback_location: settings_notifications_path, alert: I18n.t('unable_to_save')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class PersonalizationSettingsController < ApplicationController
|
|||||||
@account_config.save!
|
@account_config.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_back(fallback_location: settings_personalization_path, notice: 'Settings have been saved.')
|
redirect_back(fallback_location: settings_personalization_path, notice: I18n.t('settings_have_been_saved'))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class ProfileController < ApplicationController
|
|||||||
|
|
||||||
def update_contact
|
def update_contact
|
||||||
if current_user.update(contact_params)
|
if current_user.update(contact_params)
|
||||||
redirect_to settings_profile_index_path, notice: 'Contact information has been updated'
|
redirect_to settings_profile_index_path, notice: I18n.t('contact_information_has_been_update')
|
||||||
else
|
else
|
||||||
render :index, status: :unprocessable_entity
|
render :index, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
@@ -18,7 +18,7 @@ class ProfileController < ApplicationController
|
|||||||
def update_password
|
def update_password
|
||||||
if current_user.update(password_params)
|
if current_user.update(password_params)
|
||||||
bypass_sign_in(current_user)
|
bypass_sign_in(current_user)
|
||||||
redirect_to settings_profile_index_path, notice: 'Password has been changed'
|
redirect_to settings_profile_index_path, notice: I18n.t('password_has_been_changed')
|
||||||
else
|
else
|
||||||
render :index, status: :unprocessable_entity
|
render :index, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ class SendSubmissionEmailController < ApplicationController
|
|||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
skip_authorization_check
|
skip_authorization_check
|
||||||
|
|
||||||
|
SEND_DURATION = 30.minutes
|
||||||
|
|
||||||
def success; end
|
def success; end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@@ -23,7 +25,10 @@ class SendSubmissionEmailController < ApplicationController
|
|||||||
|
|
||||||
RateLimit.call("send-email-#{@submitter.id}", limit: 2, ttl: 5.minutes)
|
RateLimit.call("send-email-#{@submitter.id}", limit: 2, ttl: 5.minutes)
|
||||||
|
|
||||||
SubmitterMailer.documents_copy_email(@submitter, sig: true).deliver_later!
|
unless EmailEvent.exists?(tag: :submitter_documents_copy, email: @submitter.email, emailable: @submitter,
|
||||||
|
event_type: :send, created_at: SEND_DURATION.ago..Time.current)
|
||||||
|
SubmitterMailer.documents_copy_email(@submitter, sig: true).deliver_later!
|
||||||
|
end
|
||||||
|
|
||||||
respond_to do |f|
|
respond_to do |f|
|
||||||
f.html { redirect_to success_send_submission_email_index_path }
|
f.html { redirect_to success_send_submission_email_index_path }
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class SessionsController < Devise::SessionsController
|
|||||||
Rollbar.warning('Sign in new user') if defined?(Rollbar)
|
Rollbar.warning('Sign in new user') if defined?(Rollbar)
|
||||||
|
|
||||||
return redirect_to new_registration_path(sign_up: true, user: sign_in_params.slice(:email)),
|
return redirect_to new_registration_path(sign_up: true, user: sign_in_params.slice(:email)),
|
||||||
notice: 'Create a new account'
|
notice: I18n.t('create_a_new_account')
|
||||||
end
|
end
|
||||||
|
|
||||||
if User.exists?(email:, otp_required_for_login: true) && sign_in_params[:otp_attempt].blank?
|
if User.exists?(email:, otp_required_for_login: true) && sign_in_params[:otp_attempt].blank?
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SetupController < ApplicationController
|
|||||||
@encrypted_config = EncryptedConfig.new(encrypted_config_params)
|
@encrypted_config = EncryptedConfig.new(encrypted_config_params)
|
||||||
|
|
||||||
unless URI.parse(encrypted_config_params[:value].to_s).class.in?([URI::HTTP, URI::HTTPS])
|
unless URI.parse(encrypted_config_params[:value].to_s).class.in?([URI::HTTP, URI::HTTPS])
|
||||||
@encrypted_config.errors.add(:value, 'should be a valid URL')
|
@encrypted_config.errors.add(:value, I18n.t('should_be_a_valid_url'))
|
||||||
|
|
||||||
return render :index, status: :unprocessable_entity
|
return render :index, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
@@ -56,7 +56,7 @@ class SetupController < ApplicationController
|
|||||||
def account_params
|
def account_params
|
||||||
return {} unless params[:account]
|
return {} unless params[:account]
|
||||||
|
|
||||||
params.require(:account).permit(:name, :timezone)
|
params.require(:account).permit(:name, :timezone, :locale)
|
||||||
end
|
end
|
||||||
|
|
||||||
def encrypted_config_params
|
def encrypted_config_params
|
||||||
@@ -66,10 +66,10 @@ class SetupController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def redirect_to_root_if_signed
|
def redirect_to_root_if_signed
|
||||||
redirect_to root_path, notice: 'You are already signed in'
|
redirect_to root_path, notice: I18n.t('you_are_already_signed_in')
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_first_user_not_created!
|
def ensure_first_user_not_created!
|
||||||
redirect_to new_user_session_path, notice: 'Please sign in.' if User.exists?
|
redirect_to new_user_session_path, notice: I18n.t('please_sign_in') if User.exists?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -11,30 +11,29 @@ class StartFormController < ApplicationController
|
|||||||
|
|
||||||
def show
|
def show
|
||||||
@submitter = @template.submissions.new(account_id: @template.account_id)
|
@submitter = @template.submissions.new(account_id: @template.account_id)
|
||||||
.submitters.new(uuid: @template.submitters.first['uuid'])
|
.submitters.new(uuid: (filter_undefined_submitters(@template).first ||
|
||||||
|
@template.submitters.first)['uuid'])
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
return redirect_to start_form_path(@template.slug) if @template.archived_at?
|
return redirect_to start_form_path(@template.slug) if @template.archived_at?
|
||||||
|
|
||||||
@submitter = Submitter.where(submission: @template.submissions.where(expire_at: Time.current..)
|
@submitter = find_or_initialize_submitter(@template, submitter_params)
|
||||||
.or(@template.submissions.where(expire_at: nil)).where(archived_at: nil))
|
|
||||||
.order(id: :desc)
|
|
||||||
.then { |rel| params[:resubmit].present? ? rel.where(completed_at: nil) : rel }
|
|
||||||
.find_or_initialize_by(**submitter_params.compact_blank)
|
|
||||||
|
|
||||||
if @submitter.completed_at?
|
if @submitter.completed_at?
|
||||||
redirect_to start_form_completed_path(@template.slug, email: submitter_params[:email])
|
redirect_to start_form_completed_path(@template.slug, email: submitter_params[:email])
|
||||||
else
|
else
|
||||||
if @template.submitters.to_a.size > 1 && @submitter.new_record?
|
if filter_undefined_submitters(@template).size > 1 && @submitter.new_record?
|
||||||
@error_message = 'Not found'
|
@error_message = I18n.t('not_found')
|
||||||
|
|
||||||
return render :show
|
return render :show
|
||||||
end
|
end
|
||||||
|
|
||||||
assign_submission_attributes(@submitter, @template) if @submitter.new_record?
|
if (is_new_record = @submitter.new_record?)
|
||||||
|
assign_submission_attributes(@submitter, @template)
|
||||||
|
|
||||||
is_new_record = @submitter.new_record?
|
Submissions::AssignDefinedSubmitters.call(@submitter.submission)
|
||||||
|
end
|
||||||
|
|
||||||
if @submitter.save
|
if @submitter.save
|
||||||
if is_new_record
|
if is_new_record
|
||||||
@@ -56,14 +55,21 @@ class StartFormController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def find_or_initialize_submitter(template, submitter_params)
|
||||||
|
Submitter.where(submission: template.submissions.where(expire_at: Time.current..)
|
||||||
|
.or(template.submissions.where(expire_at: nil)).where(archived_at: nil))
|
||||||
|
.order(id: :desc)
|
||||||
|
.where(declined_at: nil)
|
||||||
|
.then { |rel| params[:resubmit].present? ? rel.where(completed_at: nil) : rel }
|
||||||
|
.find_or_initialize_by(**submitter_params.compact_blank)
|
||||||
|
end
|
||||||
|
|
||||||
def assign_submission_attributes(submitter, template)
|
def assign_submission_attributes(submitter, template)
|
||||||
resubmit_submitter =
|
resubmit_submitter =
|
||||||
if params[:resubmit].present?
|
(Submitter.where(submission: template.submissions).find_by(slug: params[:resubmit]) if params[:resubmit].present?)
|
||||||
Submitter.where(submission: @template.submissions).find_by(slug: params[:resubmit])
|
|
||||||
end
|
|
||||||
|
|
||||||
submitter.assign_attributes(
|
submitter.assign_attributes(
|
||||||
uuid: template.submitters.first['uuid'],
|
uuid: (filter_undefined_submitters(template).first || @template.submitters.first)['uuid'],
|
||||||
ip: request.remote_ip,
|
ip: request.remote_ip,
|
||||||
ua: request.user_agent,
|
ua: request.user_agent,
|
||||||
values: resubmit_submitter&.preferences&.fetch('default_values', nil) || {},
|
values: resubmit_submitter&.preferences&.fetch('default_values', nil) || {},
|
||||||
@@ -80,6 +86,7 @@ class StartFormController < ApplicationController
|
|||||||
submitter.submission ||= Submission.new(template:,
|
submitter.submission ||= Submission.new(template:,
|
||||||
account_id: template.account_id,
|
account_id: template.account_id,
|
||||||
template_submitters: template.submitters,
|
template_submitters: template.submitters,
|
||||||
|
submitters: [submitter],
|
||||||
source: :link)
|
source: :link)
|
||||||
|
|
||||||
submitter.account_id = submitter.submission.account_id
|
submitter.account_id = submitter.submission.account_id
|
||||||
@@ -87,6 +94,10 @@ class StartFormController < ApplicationController
|
|||||||
submitter
|
submitter
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def filter_undefined_submitters(template)
|
||||||
|
Templates.filter_undefined_submitters(template)
|
||||||
|
end
|
||||||
|
|
||||||
def submitter_params
|
def submitter_params
|
||||||
params.require(:submitter).permit(:email, :phone, :name).tap do |attrs|
|
params.require(:submitter).permit(:email, :phone, :name).tap do |attrs|
|
||||||
attrs[:email] = Submissions.normalize_email(attrs[:email])
|
attrs[:email] = Submissions.normalize_email(attrs[:email])
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class StorageSettingsController < ApplicationController
|
|||||||
if @encrypted_config.update(storage_configs)
|
if @encrypted_config.update(storage_configs)
|
||||||
LoadActiveStorageConfigs.reload
|
LoadActiveStorageConfigs.reload
|
||||||
|
|
||||||
redirect_to settings_storage_index_path, notice: 'Changes have been saved'
|
redirect_to settings_storage_index_path, notice: I18n.t('changes_have_been_saved')
|
||||||
else
|
else
|
||||||
render :index, status: :unprocessable_entity
|
render :index, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class SubmissionsController < ApplicationController
|
|||||||
|
|
||||||
Submissions.send_signature_requests(submissions)
|
Submissions.send_signature_requests(submissions)
|
||||||
|
|
||||||
redirect_to template_path(@template), notice: 'New recipients have been added'
|
redirect_to template_path(@template), notice: I18n.t('new_recipients_have_been_added')
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@@ -57,13 +57,13 @@ class SubmissionsController < ApplicationController
|
|||||||
if params[:permanently].present?
|
if params[:permanently].present?
|
||||||
@submission.destroy!
|
@submission.destroy!
|
||||||
|
|
||||||
'Submission has been removed'
|
I18n.t('submission_has_been_removed')
|
||||||
else
|
else
|
||||||
@submission.update!(archived_at: Time.current)
|
@submission.update!(archived_at: Time.current)
|
||||||
|
|
||||||
SendSubmissionArchivedWebhookRequestJob.perform_async('submission_id' => @submission.id)
|
SendSubmissionArchivedWebhookRequestJob.perform_async('submission_id' => @submission.id)
|
||||||
|
|
||||||
'Submission has been archived'
|
I18n.t('submission_has_been_archived')
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_back(fallback_location: template_path(@submission.template), notice:)
|
redirect_back(fallback_location: template_path(@submission.template), notice:)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class SubmissionsDownloadController < ApplicationController
|
|||||||
return head :not_found
|
return head :not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
if params[:combined]
|
if params[:combined] == 'true'
|
||||||
url = build_combined_url(submitter)
|
url = build_combined_url(submitter)
|
||||||
|
|
||||||
if url
|
if url
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SubmissionsPreviewController < ApplicationController
|
|||||||
@submission ||= Submission.find_by!(slug: params[:slug])
|
@submission ||= Submission.find_by!(slug: params[:slug])
|
||||||
|
|
||||||
if !@submission.submitters.all?(&:completed_at?) && current_user.blank?
|
if !@submission.submitters.all?(&:completed_at?) && current_user.blank?
|
||||||
raise ActionController::RoutingError, 'Not Found'
|
raise ActionController::RoutingError, I18n.t('not_found')
|
||||||
end
|
end
|
||||||
|
|
||||||
if !submission_valid_ttl?(@submission) && !signature_valid
|
if !submission_valid_ttl?(@submission) && !signature_valid
|
||||||
|
|||||||
@@ -12,15 +12,20 @@ class SubmitFormController < ApplicationController
|
|||||||
def show
|
def show
|
||||||
@submitter = Submitter.find_by!(slug: params[:slug])
|
@submitter = Submitter.find_by!(slug: params[:slug])
|
||||||
|
|
||||||
|
submission = @submitter.submission
|
||||||
|
|
||||||
return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at?
|
return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at?
|
||||||
return render :archived if @submitter.submission.template.archived_at? || @submitter.submission.archived_at?
|
return render :archived if submission.template.archived_at? || submission.archived_at?
|
||||||
return render :expired if @submitter.submission.expired?
|
return render :expired if submission.expired?
|
||||||
|
return render :declined if @submitter.declined_at?
|
||||||
|
return render :awaiting if submission.template.preferences['submitters_order'] == 'preserved' &&
|
||||||
|
!Submitters.current_submitter_order?(@submitter)
|
||||||
|
|
||||||
Submitters.preload_with_pages(@submitter)
|
Submitters.preload_with_pages(@submitter)
|
||||||
|
|
||||||
Submitters::MaybeUpdateDefaultValues.call(@submitter, current_user)
|
Submitters::MaybeUpdateDefaultValues.call(@submitter, current_user)
|
||||||
|
|
||||||
@attachments_index = ActiveStorage::Attachment.where(record: @submitter.submission.submitters, name: :attachments)
|
@attachments_index = ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments)
|
||||||
.preload(:blob).index_by(&:uuid)
|
.preload(:blob).index_by(&:uuid)
|
||||||
|
|
||||||
@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)
|
@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)
|
||||||
@@ -45,15 +50,20 @@ class SubmitFormController < ApplicationController
|
|||||||
submitter = Submitter.find_by!(slug: params[:slug])
|
submitter = Submitter.find_by!(slug: params[:slug])
|
||||||
|
|
||||||
if submitter.completed_at?
|
if submitter.completed_at?
|
||||||
return render json: { error: 'Form has been completed already.' }, status: :unprocessable_entity
|
return render json: { error: I18n.t('form_has_been_completed_already') }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|
||||||
if submitter.template.archived_at? || submitter.submission.archived_at?
|
if submitter.template.archived_at? || submitter.submission.archived_at?
|
||||||
return render json: { error: 'Form has been archived.' }, status: :unprocessable_entity
|
return render json: { error: I18n.t('form_has_been_archived') }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|
||||||
if submitter.submission.expired?
|
if submitter.submission.expired?
|
||||||
return render json: { error: 'Form has been expired.' }, status: :unprocessable_entity
|
return render json: { error: I18n.t('form_has_been_expired') }, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
|
||||||
|
if submitter.declined_at?
|
||||||
|
return render json: { error: I18n.t('form_has_been_declined') },
|
||||||
|
status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|
||||||
Submitters::SubmitValues.call(submitter, params, request)
|
Submitters::SubmitValues.call(submitter, params, request)
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SubmitFormDeclineController < ApplicationController
|
||||||
|
skip_before_action :authenticate_user!
|
||||||
|
skip_authorization_check
|
||||||
|
|
||||||
|
def create
|
||||||
|
submitter = Submitter.find_by!(slug: params[:submit_form_slug])
|
||||||
|
|
||||||
|
return redirect_to submit_form_path(submitter.slug) if submitter.declined_at? ||
|
||||||
|
submitter.completed_at? ||
|
||||||
|
submitter.submission.archived_at? ||
|
||||||
|
submitter.submission.expired? ||
|
||||||
|
submitter.submission.template.archived_at?
|
||||||
|
|
||||||
|
ApplicationRecord.transaction do
|
||||||
|
submitter.update!(declined_at: Time.current)
|
||||||
|
|
||||||
|
SubmissionEvents.create_with_tracking_data(submitter, 'decline_form', request, { reason: params[:reason] })
|
||||||
|
end
|
||||||
|
|
||||||
|
user = submitter.submission.created_by_user || submitter.template.author
|
||||||
|
|
||||||
|
SubmitterMailer.declined_email(submitter, user).deliver_later!
|
||||||
|
SendFormDeclinedWebhookRequestJob.perform_async('submitter_id' => submitter.id)
|
||||||
|
|
||||||
|
redirect_to submit_form_path(submitter.slug)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SubmitFormDownloadController < ApplicationController
|
||||||
|
skip_before_action :authenticate_user!
|
||||||
|
skip_authorization_check
|
||||||
|
|
||||||
|
FILES_TTL = 5.minutes
|
||||||
|
|
||||||
|
def index
|
||||||
|
submitter = Submitter.find_by!(slug: params[:submit_form_slug])
|
||||||
|
|
||||||
|
return redirect_to submitter_download_index_path(submitter.slug) if submitter.completed_at?
|
||||||
|
|
||||||
|
return head :unprocessable_entity if submitter.declined_at? ||
|
||||||
|
submitter.submission.archived_at? ||
|
||||||
|
submitter.submission.expired? ||
|
||||||
|
submitter.submission.template.archived_at?
|
||||||
|
|
||||||
|
last_completed_submitter = submitter.submission.submitters
|
||||||
|
.where.not(id: submitter.id)
|
||||||
|
.where.not(completed_at: nil)
|
||||||
|
.max_by(&:completed_at)
|
||||||
|
|
||||||
|
attachments =
|
||||||
|
if last_completed_submitter
|
||||||
|
Submitters.select_attachments_for_download(last_completed_submitter)
|
||||||
|
else
|
||||||
|
submitter.submission.template.schema_documents.preload(:blob)
|
||||||
|
end
|
||||||
|
|
||||||
|
urls = attachments.map do |attachment|
|
||||||
|
ActiveStorage::Blob.proxy_url(attachment.blob, expires_at: FILES_TTL.from_now.to_i)
|
||||||
|
end
|
||||||
|
|
||||||
|
render json: urls
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SubmitFormInviteController < ApplicationController
|
||||||
|
skip_before_action :authenticate_user!
|
||||||
|
skip_authorization_check
|
||||||
|
|
||||||
|
def create
|
||||||
|
submitter = Submitter.find_by!(slug: params[:submit_form_slug])
|
||||||
|
|
||||||
|
return head :unprocessable_entity unless can_invite?(submitter)
|
||||||
|
|
||||||
|
invite_submitters = filter_invite_submitters(submitter)
|
||||||
|
|
||||||
|
ApplicationRecord.transaction do
|
||||||
|
invite_submitters.each do |item|
|
||||||
|
attrs = submitters_attributes.find { |e| e[:uuid] == item['uuid'] }
|
||||||
|
|
||||||
|
next unless attrs
|
||||||
|
|
||||||
|
submitter.submission.submitters.create!(**attrs, account_id: submitter.account_id)
|
||||||
|
|
||||||
|
SubmissionEvents.create_with_tracking_data(submitter, 'invite_party', request, { uuid: submitter.uuid })
|
||||||
|
end
|
||||||
|
|
||||||
|
submitter.submission.update!(submitters_order: :preserved)
|
||||||
|
end
|
||||||
|
|
||||||
|
submitter.submission.submitters.reload
|
||||||
|
|
||||||
|
if invite_submitters.all? { |s| submitter.submission.submitters.any? { |e| e.uuid == s['uuid'] } }
|
||||||
|
Submitters::SubmitValues.call(submitter, ActionController::Parameters.new(completed: 'true'), request)
|
||||||
|
|
||||||
|
head :ok
|
||||||
|
else
|
||||||
|
head :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def can_invite?(submitter)
|
||||||
|
!submitter.declined_at? &&
|
||||||
|
!submitter.completed_at? &&
|
||||||
|
!submitter.submission.archived_at? &&
|
||||||
|
!submitter.submission.expired? &&
|
||||||
|
!submitter.submission.template.archived_at?
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_invite_submitters(submitter)
|
||||||
|
(submitter.submission.template_submitters || submitter.submission.template.submitters).select do |s|
|
||||||
|
s['invite_by_uuid'] == submitter.uuid && submitter.submission.submitters.none? { |e| e.uuid == s['uuid'] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def submitters_attributes
|
||||||
|
params.require(:submission).permit(submitters: [%i[uuid email]]).fetch(:submitters, [])
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -7,8 +7,10 @@ class SubmitFormValuesController < ApplicationController
|
|||||||
def index
|
def index
|
||||||
submitter = Submitter.find_by!(slug: params[:submit_form_slug])
|
submitter = Submitter.find_by!(slug: params[:submit_form_slug])
|
||||||
|
|
||||||
return render json: {} if submitter.completed_at?
|
return render json: {} if submitter.completed_at? || submitter.declined_at?
|
||||||
return render json: {} if submitter.submission.template.archived_at? || submitter.submission.archived_at?
|
return render json: {} if submitter.submission.template.archived_at? ||
|
||||||
|
submitter.submission.archived_at? ||
|
||||||
|
submitter.submission.expired?
|
||||||
|
|
||||||
value = submitter.values[params['field_uuid']]
|
value = submitter.values[params['field_uuid']]
|
||||||
attachment = submitter.attachments.where(created_at: params[:after]..).find_by(uuid: value) if value.present?
|
attachment = submitter.attachments.where(created_at: params[:after]..).find_by(uuid: value) if value.present?
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class SubmittersSendEmailController < ApplicationController
|
|||||||
Rollbar.warning("Already sent: #{@submitter.id}") if defined?(Rollbar)
|
Rollbar.warning("Already sent: #{@submitter.id}") if defined?(Rollbar)
|
||||||
|
|
||||||
return redirect_back(fallback_location: submission_path(@submitter.submission),
|
return redirect_back(fallback_location: submission_path(@submitter.submission),
|
||||||
alert: 'Email has been sent already.')
|
alert: I18n.t('email_has_been_sent_already'))
|
||||||
end
|
end
|
||||||
|
|
||||||
SendSubmitterInvitationEmailJob.perform_async('submitter_id' => @submitter.id)
|
SendSubmitterInvitationEmailJob.perform_async('submitter_id' => @submitter.id)
|
||||||
@@ -18,6 +18,6 @@ class SubmittersSendEmailController < ApplicationController
|
|||||||
@submitter.sent_at ||= Time.current
|
@submitter.sent_at ||= Time.current
|
||||||
@submitter.save!
|
@submitter.save!
|
||||||
|
|
||||||
redirect_back(fallback_location: submission_path(@submitter.submission), notice: 'Email has been sent')
|
redirect_back(fallback_location: submission_path(@submitter.submission), notice: I18n.t('email_has_been_sent'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -5,7 +5,7 @@ class TemplateDocumentsController < ApplicationController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
if params[:blobs].blank? && params[:files].blank?
|
if params[:blobs].blank? && params[:files].blank?
|
||||||
return render json: { error: 'File is missing' }, status: :unprocessable_entity
|
return render json: { error: I18n.t('file_is_missing') }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|
||||||
old_fields_hash = @template.fields.hash
|
old_fields_hash = @template.fields.hash
|
||||||
@@ -28,6 +28,6 @@ class TemplateDocumentsController < ApplicationController
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
rescue Templates::CreateAttachments::PdfEncrypted
|
rescue Templates::CreateAttachments::PdfEncrypted
|
||||||
render json: { error: 'PDF encrypted' }, status: :unprocessable_entity
|
render json: { error: 'PDF encrypted', status: 'pdf_encrypted' }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -7,7 +7,7 @@ class TemplateFoldersController < ApplicationController
|
|||||||
@templates = @template_folder.templates.active.preload(:author).order(id: :desc)
|
@templates = @template_folder.templates.active.preload(:author).order(id: :desc)
|
||||||
@templates = Templates.search(@templates, params[:q])
|
@templates = Templates.search(@templates, params[:q])
|
||||||
|
|
||||||
@pagy, @templates = pagy(@templates, items: 12)
|
@pagy, @templates = pagy(@templates, limit: 12)
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit; end
|
def edit; end
|
||||||
@@ -15,9 +15,9 @@ class TemplateFoldersController < ApplicationController
|
|||||||
def update
|
def update
|
||||||
if @template_folder != current_account.default_template_folder &&
|
if @template_folder != current_account.default_template_folder &&
|
||||||
@template_folder.update(template_folder_params)
|
@template_folder.update(template_folder_params)
|
||||||
redirect_to folder_path(@template_folder), notice: 'Folder name has been updated'
|
redirect_to folder_path(@template_folder), notice: I18n.t('folder_name_has_been_updated')
|
||||||
else
|
else
|
||||||
redirect_to folder_path(@template_folder), alert: 'Unable to rename folder'
|
redirect_to folder_path(@template_folder), alert: I18n.t('unable_to_rename_folder')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ class TemplatesArchivedController < ApplicationController
|
|||||||
@templates = @templates.where.not(archived_at: nil).preload(:author, :folder).order(id: :desc)
|
@templates = @templates.where.not(archived_at: nil).preload(:author, :folder).order(id: :desc)
|
||||||
@templates = Templates.search(@templates, params[:q])
|
@templates = Templates.search(@templates, params[:q])
|
||||||
|
|
||||||
@pagy, @templates = pagy(@templates, items: 12)
|
@pagy, @templates = pagy(@templates, limit: 12)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -21,7 +21,7 @@ class TemplatesController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@template.name = "#{@base_template.name} (Clone)" if @base_template
|
@template.name = "#{@base_template.name} (#{I18n.t('clone')})" if @base_template
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@@ -87,11 +87,11 @@ class TemplatesController < ApplicationController
|
|||||||
if params[:permanently].present?
|
if params[:permanently].present?
|
||||||
@template.destroy!
|
@template.destroy!
|
||||||
|
|
||||||
'Template has been removed.'
|
I18n.t('template_has_been_removed')
|
||||||
else
|
else
|
||||||
@template.update!(archived_at: Time.current)
|
@template.update!(archived_at: Time.current)
|
||||||
|
|
||||||
'Template has been archived.'
|
I18n.t('template_has_been_archived')
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_back(fallback_location: root_path, notice:)
|
redirect_back(fallback_location: root_path, notice:)
|
||||||
@@ -103,7 +103,7 @@ class TemplatesController < ApplicationController
|
|||||||
params.require(:template).permit(
|
params.require(:template).permit(
|
||||||
:name,
|
:name,
|
||||||
{ schema: [%i[attachment_uuid name]],
|
{ schema: [%i[attachment_uuid name]],
|
||||||
submitters: [%i[name uuid]],
|
submitters: [%i[name uuid is_requester linked_to_uuid invite_by_uuid email]],
|
||||||
fields: [[:uuid, :submitter_uuid, :name, :type,
|
fields: [[:uuid, :submitter_uuid, :name, :type,
|
||||||
:required, :readonly, :default_value,
|
:required, :readonly, :default_value,
|
||||||
:title, :description,
|
:title, :description,
|
||||||
@@ -116,14 +116,15 @@ class TemplatesController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def authorized_clone_account_id?(account_id)
|
def authorized_clone_account_id?(account_id)
|
||||||
true_user.account_id.to_s == account_id.to_s || true_user.account.linked_accounts.exists?(id: account_id)
|
true_user.account_id.to_s == account_id.to_s ||
|
||||||
|
true_user.account.linked_accounts.accessible_by(current_ability).exists?(id: account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_redirect_to_template(template)
|
def maybe_redirect_to_template(template)
|
||||||
if template.account == current_account
|
if template.account == current_account
|
||||||
redirect_to(edit_template_path(@template))
|
redirect_to(edit_template_path(@template))
|
||||||
else
|
else
|
||||||
redirect_back(fallback_location: root_path, notice: 'Template has been clonned')
|
redirect_back(fallback_location: root_path, notice: I18n.t('template_has_been_cloned'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ class TemplatesDashboardController < ApplicationController
|
|||||||
@template_folders = @template_folders.reject { |e| e.name == TemplateFolder::DEFAULT_NAME }
|
@template_folders = @template_folders.reject { |e| e.name == TemplateFolder::DEFAULT_NAME }
|
||||||
@templates = filter_templates(@templates)
|
@templates = filter_templates(@templates)
|
||||||
|
|
||||||
items =
|
limit =
|
||||||
if @template_folders.size < 4
|
if @template_folders.size < 4
|
||||||
TEMPLATES_PER_PAGE
|
TEMPLATES_PER_PAGE
|
||||||
else
|
else
|
||||||
(@template_folders.size < 7 ? 9 : 6)
|
(@template_folders.size < 7 ? 9 : 6)
|
||||||
end
|
end
|
||||||
|
|
||||||
@pagy, @templates = pagy(@templates, items:)
|
@pagy, @templates = pagy(@templates, limit:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ class TemplatesFoldersController < ApplicationController
|
|||||||
@template.folder = TemplateFolders.find_or_create_by_name(current_user, params[:name])
|
@template.folder = TemplateFolders.find_or_create_by_name(current_user, params[:name])
|
||||||
|
|
||||||
if @template.save
|
if @template.save
|
||||||
redirect_back(fallback_location: template_path(@template), notice: 'Document template has been moved')
|
redirect_back(fallback_location: template_path(@template), notice: I18n.t('document_template_has_been_moved'))
|
||||||
else
|
else
|
||||||
redirect_back(fallback_location: template_path(@template), notice: 'Unable to move template into folder')
|
redirect_back(fallback_location: template_path(@template), notice: I18n.t('unable_to_move_template_into_folder'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class TemplatesPreferencesController < ApplicationController
|
|||||||
authorize!(:update, @template)
|
authorize!(:update, @template)
|
||||||
|
|
||||||
@template.preferences = @template.preferences.merge(template_params[:preferences])
|
@template.preferences = @template.preferences.merge(template_params[:preferences])
|
||||||
@template.preferences = @template.preferences.reject { |_, v| v.is_a?(String) && v.blank? }
|
@template.preferences = @template.preferences.reject { |_, v| (v.is_a?(String) || v.is_a?(Hash)) && v.blank? }
|
||||||
@template.save!
|
@template.save!
|
||||||
|
|
||||||
head :ok
|
head :ok
|
||||||
@@ -23,12 +23,17 @@ class TemplatesPreferencesController < ApplicationController
|
|||||||
documents_copy_email_subject documents_copy_email_body
|
documents_copy_email_subject documents_copy_email_body
|
||||||
documents_copy_email_enabled documents_copy_email_attach_audit
|
documents_copy_email_enabled documents_copy_email_attach_audit
|
||||||
completed_notification_email_attach_documents
|
completed_notification_email_attach_documents
|
||||||
|
completed_redirect_url
|
||||||
|
submitters_order
|
||||||
completed_notification_email_subject completed_notification_email_body
|
completed_notification_email_subject completed_notification_email_body
|
||||||
completed_notification_email_enabled completed_notification_email_attach_audit]
|
completed_notification_email_enabled completed_notification_email_attach_audit] +
|
||||||
|
[completed_message: %i[title body]]
|
||||||
).tap do |attrs|
|
).tap do |attrs|
|
||||||
attrs[:preferences] = attrs[:preferences].transform_values do |value|
|
attrs[:preferences] = attrs[:preferences].transform_values do |value|
|
||||||
if %w[true false].include?(value)
|
if %w[true false].include?(value)
|
||||||
value == 'true'
|
value == 'true'
|
||||||
|
elsif value.respond_to?(:compact_blank)
|
||||||
|
value.compact_blank
|
||||||
else
|
else
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class TemplatesRecipientsController < ApplicationController
|
||||||
|
load_and_authorize_resource :template
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize!(:update, @template)
|
||||||
|
|
||||||
|
@template.submitters =
|
||||||
|
submitters_params.map { |s| s.reject { |_, v| v.is_a?(String) && v.blank? } }
|
||||||
|
|
||||||
|
@template.save!
|
||||||
|
|
||||||
|
render json: { submitters: @template.submitters }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def submitters_params
|
||||||
|
params.require(:template).permit(
|
||||||
|
submitters: [%i[name uuid is_requester invite_by_uuid linked_to_uuid email option]]
|
||||||
|
).fetch(:submitters, {}).values.filter_map do |s|
|
||||||
|
next if s[:uuid].blank?
|
||||||
|
|
||||||
|
if s[:is_requester] == '1' && s[:invite_by_uuid].blank?
|
||||||
|
s[:is_requester] = true
|
||||||
|
else
|
||||||
|
s.delete(:is_requester)
|
||||||
|
end
|
||||||
|
|
||||||
|
s.delete(:invite_by_uuid) if s[:invite_by_uuid].blank?
|
||||||
|
|
||||||
|
option = s.delete(:option)
|
||||||
|
|
||||||
|
if option.present?
|
||||||
|
case option
|
||||||
|
when 'is_requester'
|
||||||
|
s[:is_requester] = true
|
||||||
|
when 'not_set'
|
||||||
|
s.delete(:is_requester)
|
||||||
|
s.delete(:email)
|
||||||
|
s.delete(:linked_to_uuid)
|
||||||
|
s.delete(:invite_by_uuid)
|
||||||
|
when /\Alinked_to_(.*)\z/
|
||||||
|
s[:linked_to_uuid] = ::Regexp.last_match(-1)
|
||||||
|
when /\Ainvite_by_(.*)\z/
|
||||||
|
s[:invite_by_uuid] = ::Regexp.last_match(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -6,6 +6,6 @@ class TemplatesRestoreController < ApplicationController
|
|||||||
def create
|
def create
|
||||||
@template.update!(archived_at: nil)
|
@template.update!(archived_at: nil)
|
||||||
|
|
||||||
redirect_to template_path(@template), notice: 'Template has been unarchived'
|
redirect_to template_path(@template), notice: I18n.t('template_has_been_unarchived')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -33,7 +33,7 @@ class TemplatesUploadsController < ApplicationController
|
|||||||
|
|
||||||
raise if Rails.env.local?
|
raise if Rails.env.local?
|
||||||
|
|
||||||
redirect_to root_path, alert: 'Unable to upload file'
|
redirect_to root_path, alert: I18n.t('unable_to_update_file')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -52,7 +52,7 @@ class TemplatesUploadsController < ApplicationController
|
|||||||
def create_file_params_from_url
|
def create_file_params_from_url
|
||||||
tempfile = Tempfile.new
|
tempfile = Tempfile.new
|
||||||
tempfile.binmode
|
tempfile.binmode
|
||||||
tempfile.write(conn.get(Addressable::URI.parse(params[:url]).display_uri.to_s).body)
|
tempfile.write(DownloadUtils.call(params[:url]).body)
|
||||||
tempfile.rewind
|
tempfile.rewind
|
||||||
|
|
||||||
file = ActionDispatch::Http::UploadedFile.new(
|
file = ActionDispatch::Http::UploadedFile.new(
|
||||||
@@ -65,10 +65,4 @@ class TemplatesUploadsController < ApplicationController
|
|||||||
|
|
||||||
{ files: [file] }
|
{ files: [file] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def conn
|
|
||||||
Faraday.new do |faraday|
|
|
||||||
faraday.response :follow_redirects
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
@@ -14,12 +14,12 @@ class TimestampServerController < ApplicationController
|
|||||||
test_timeserver_url(@encrypted_config.value) if @encrypted_config.value.present?
|
test_timeserver_url(@encrypted_config.value) if @encrypted_config.value.present?
|
||||||
|
|
||||||
if @encrypted_config.value.present? ? @encrypted_config.save : @encrypted_config.delete
|
if @encrypted_config.value.present? ? @encrypted_config.save : @encrypted_config.delete
|
||||||
redirect_back fallback_location: settings_notifications_path, notice: 'Changes have been saved'
|
redirect_back fallback_location: settings_notifications_path, notice: I18n.t('changes_have_been_saved')
|
||||||
else
|
else
|
||||||
redirect_back fallback_location: settings_notifications_path, alert: 'Unable to save'
|
redirect_back fallback_location: settings_notifications_path, alert: I18n.t('unable_to_save')
|
||||||
end
|
end
|
||||||
rescue SocketError, TimestampError, OpenSSL::Timestamp::TimestampError
|
rescue SocketError, TimestampError, OpenSSL::Timestamp::TimestampError
|
||||||
redirect_back fallback_location: settings_notifications_path, alert: 'Invalid Timeserver'
|
redirect_back fallback_location: settings_notifications_path, alert: t('invalid_timeserver')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class UserInitialsController < ApplicationController
|
|||||||
def update
|
def update
|
||||||
file = params[:file]
|
file = params[:file]
|
||||||
|
|
||||||
return redirect_to settings_profile_index_path, notice: 'Unable to save initials' if file.blank?
|
return redirect_to settings_profile_index_path, notice: I18n.t('unable_to_save_initials') if file.blank?
|
||||||
|
|
||||||
blob = ActiveStorage::Blob.create_and_upload!(io: file.open,
|
blob = ActiveStorage::Blob.create_and_upload!(io: file.open,
|
||||||
filename: file.original_filename,
|
filename: file.original_filename,
|
||||||
@@ -22,16 +22,16 @@ class UserInitialsController < ApplicationController
|
|||||||
)
|
)
|
||||||
|
|
||||||
if @user_config.update(value: attachment.uuid)
|
if @user_config.update(value: attachment.uuid)
|
||||||
redirect_to settings_profile_index_path, notice: 'Initials has been saved'
|
redirect_to settings_profile_index_path, notice: I18n.t('initials_has_been_saved')
|
||||||
else
|
else
|
||||||
redirect_to settings_profile_index_path, notice: 'Unable to save initials'
|
redirect_to settings_profile_index_path, notice: I18n.t('unable_to_save_initials')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@user_config.destroy
|
@user_config.destroy
|
||||||
|
|
||||||
redirect_to settings_profile_index_path, notice: 'Initials has been removed'
|
redirect_to settings_profile_index_path, notice: I18n.t('initials_has_been_removed')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class UserSignaturesController < ApplicationController
|
|||||||
def update
|
def update
|
||||||
file = params[:file]
|
file = params[:file]
|
||||||
|
|
||||||
return redirect_to settings_profile_index_path, notice: 'Unable to save signature' if file.blank?
|
return redirect_to settings_profile_index_path, notice: I18n.t('unable_to_save_signature') if file.blank?
|
||||||
|
|
||||||
blob = ActiveStorage::Blob.create_and_upload!(io: file.open,
|
blob = ActiveStorage::Blob.create_and_upload!(io: file.open,
|
||||||
filename: file.original_filename,
|
filename: file.original_filename,
|
||||||
@@ -22,16 +22,16 @@ class UserSignaturesController < ApplicationController
|
|||||||
)
|
)
|
||||||
|
|
||||||
if @user_config.update(value: attachment.uuid)
|
if @user_config.update(value: attachment.uuid)
|
||||||
redirect_to settings_profile_index_path, notice: 'Signature has been saved'
|
redirect_to settings_profile_index_path, notice: I18n.t('signature_has_been_saved')
|
||||||
else
|
else
|
||||||
redirect_to settings_profile_index_path, notice: 'Unable to save signature'
|
redirect_to settings_profile_index_path, notice: I18n.t('unable_to_save_signature')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@user_config.destroy
|
@user_config.destroy
|
||||||
|
|
||||||
redirect_to settings_profile_index_path, notice: 'Signature has been removed'
|
redirect_to settings_profile_index_path, notice: I18n.t('signature_has_been_removed')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ class UsersController < ApplicationController
|
|||||||
if @user.save
|
if @user.save
|
||||||
UserMailer.invitation_email(@user).deliver_later!
|
UserMailer.invitation_email(@user).deliver_later!
|
||||||
|
|
||||||
redirect_back fallback_location: settings_users_path, notice: 'User has been invited'
|
redirect_back fallback_location: settings_users_path, notice: I18n.t('user_has_been_invited')
|
||||||
else
|
else
|
||||||
render turbo_stream: turbo_stream.replace(:modal, template: 'users/new'), status: :unprocessable_entity
|
render turbo_stream: turbo_stream.replace(:modal, template: 'users/new'), status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
return redirect_to settings_users_path, notice: 'Unable to update user.' if Docuseal.demo?
|
return redirect_to settings_users_path, notice: I18n.t('unable_to_update_user') if Docuseal.demo?
|
||||||
|
|
||||||
attrs = user_params.compact_blank.merge(user_params.slice(:archived_at))
|
attrs = user_params.compact_blank.merge(user_params.slice(:archived_at))
|
||||||
attrs.delete(:role) if !role_valid?(attrs[:role]) || current_user == @user
|
attrs.delete(:role) if !role_valid?(attrs[:role]) || current_user == @user
|
||||||
@@ -56,7 +56,7 @@ class UsersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
if @user.update(attrs)
|
if @user.update(attrs)
|
||||||
redirect_back fallback_location: settings_users_path, notice: 'User has been updated'
|
redirect_back fallback_location: settings_users_path, notice: I18n.t('user_has_been_updated')
|
||||||
else
|
else
|
||||||
render turbo_stream: turbo_stream.replace(:modal, template: 'users/edit'), status: :unprocessable_entity
|
render turbo_stream: turbo_stream.replace(:modal, template: 'users/edit'), status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
@@ -64,12 +64,12 @@ class UsersController < ApplicationController
|
|||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
if Docuseal.demo? || @user.id == current_user.id
|
if Docuseal.demo? || @user.id == current_user.id
|
||||||
return redirect_to settings_users_path, notice: 'Unable to remove user'
|
return redirect_to settings_users_path, notice: I18n.t('unable_to_remove_user')
|
||||||
end
|
end
|
||||||
|
|
||||||
@user.update!(archived_at: Time.current)
|
@user.update!(archived_at: Time.current)
|
||||||
|
|
||||||
redirect_back fallback_location: settings_users_path, notice: 'User has been removed'
|
redirect_back fallback_location: settings_users_path, notice: I18n.t('user_has_been_removed')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ class VerifyPdfSignatureController < ApplicationController
|
|||||||
render turbo_stream: turbo_stream.replace('result', partial: 'result',
|
render turbo_stream: turbo_stream.replace('result', partial: 'result',
|
||||||
locals: { pdfs:, files: params[:files], trusted_certs: })
|
locals: { pdfs:, files: params[:files], trusted_certs: })
|
||||||
rescue HexaPDF::MalformedPDFError
|
rescue HexaPDF::MalformedPDFError
|
||||||
render turbo_stream: turbo_stream.replace('result', html: helpers.tag.div('Invalid PDF', id: 'result'))
|
render turbo_stream: turbo_stream.replace('result', html: helpers.tag.div(I18n.t('invalid_pdf'), id: 'result'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -5,6 +5,7 @@ class WebhookPreferencesController < ApplicationController
|
|||||||
form.viewed
|
form.viewed
|
||||||
form.started
|
form.started
|
||||||
form.completed
|
form.completed
|
||||||
|
form.declined
|
||||||
template.created
|
template.created
|
||||||
template.updated
|
template.updated
|
||||||
submission.created
|
submission.created
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class WebhookSecretController < ApplicationController
|
|||||||
|
|
||||||
@encrypted_config.value.present? ? @encrypted_config.save! : @encrypted_config.delete
|
@encrypted_config.value.present? ? @encrypted_config.save! : @encrypted_config.delete
|
||||||
|
|
||||||
redirect_back(fallback_location: settings_webhooks_path, notice: 'Webhook Secret has been saved.')
|
redirect_back(fallback_location: settings_webhooks_path, notice: I18n.t('webhook_secret_has_been_saved'))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class WebhookSettingsController < ApplicationController
|
|||||||
|
|
||||||
@encrypted_config.value.present? ? @encrypted_config.save! : @encrypted_config.delete
|
@encrypted_config.value.present? ? @encrypted_config.save! : @encrypted_config.delete
|
||||||
|
|
||||||
redirect_back(fallback_location: settings_webhooks_path, notice: 'Webhook URL has been saved.')
|
redirect_back(fallback_location: settings_webhooks_path, notice: I18n.t('webhook_url_has_been_saved'))
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@@ -20,7 +20,7 @@ class WebhookSettingsController < ApplicationController
|
|||||||
SendFormCompletedWebhookRequestJob.perform_async({ 'submitter_id' => submitter.id,
|
SendFormCompletedWebhookRequestJob.perform_async({ 'submitter_id' => submitter.id,
|
||||||
'encrypted_config_id' => @encrypted_config.id })
|
'encrypted_config_id' => @encrypted_config.id })
|
||||||
|
|
||||||
redirect_back(fallback_location: settings_webhooks_path, notice: 'Webhook request has been sent.')
|
redirect_back(fallback_location: settings_webhooks_path, notice: I18n.t('webhook_request_has_been_sent'))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ import EmailsTextarea from './elements/emails_textarea'
|
|||||||
import ToggleOnSubmit from './elements/toggle_on_submit'
|
import ToggleOnSubmit from './elements/toggle_on_submit'
|
||||||
import PasswordInput from './elements/password_input'
|
import PasswordInput from './elements/password_input'
|
||||||
import SearchInput from './elements/search_input'
|
import SearchInput from './elements/search_input'
|
||||||
|
import ToggleAttribute from './elements/toggle_attribute'
|
||||||
|
import LinkedInput from './elements/linked_input'
|
||||||
|
import CheckboxGroup from './elements/checkbox_group'
|
||||||
|
|
||||||
import * as TurboInstantClick from './lib/turbo_instant_click'
|
import * as TurboInstantClick from './lib/turbo_instant_click'
|
||||||
|
|
||||||
@@ -89,9 +92,14 @@ safeRegisterElement('toggle-cookies', ToggleCookies)
|
|||||||
safeRegisterElement('toggle-on-submit', ToggleOnSubmit)
|
safeRegisterElement('toggle-on-submit', ToggleOnSubmit)
|
||||||
safeRegisterElement('password-input', PasswordInput)
|
safeRegisterElement('password-input', PasswordInput)
|
||||||
safeRegisterElement('search-input', SearchInput)
|
safeRegisterElement('search-input', SearchInput)
|
||||||
|
safeRegisterElement('toggle-attribute', ToggleAttribute)
|
||||||
|
safeRegisterElement('linked-input', LinkedInput)
|
||||||
|
safeRegisterElement('checkbox-group', CheckboxGroup)
|
||||||
|
|
||||||
safeRegisterElement('template-builder', class extends HTMLElement {
|
safeRegisterElement('template-builder', class extends HTMLElement {
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
|
document.addEventListener('turbo:submit-end', this.onSubmit)
|
||||||
|
|
||||||
this.appElem = document.createElement('div')
|
this.appElem = document.createElement('div')
|
||||||
|
|
||||||
this.appElem.classList.add('md:h-screen')
|
this.appElem.classList.add('md:h-screen')
|
||||||
@@ -107,17 +115,29 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
|||||||
withPayment: this.dataset.withPayment === 'true',
|
withPayment: this.dataset.withPayment === 'true',
|
||||||
isPaymentConnected: this.dataset.isPaymentConnected === 'true',
|
isPaymentConnected: this.dataset.isPaymentConnected === 'true',
|
||||||
withFormula: this.dataset.withFormula === 'true',
|
withFormula: this.dataset.withFormula === 'true',
|
||||||
|
withSendButton: this.dataset.withSendButton !== 'false',
|
||||||
|
withSignYourselfButton: this.dataset.withSignYourselfButton !== 'false',
|
||||||
withConditions: this.dataset.withConditions === 'true',
|
withConditions: this.dataset.withConditions === 'true',
|
||||||
currencies: (this.dataset.currencies || '').split(',').filter(Boolean),
|
currencies: (this.dataset.currencies || '').split(',').filter(Boolean),
|
||||||
acceptFileTypes: this.dataset.acceptFileTypes
|
acceptFileTypes: this.dataset.acceptFileTypes
|
||||||
})
|
})
|
||||||
|
|
||||||
this.app.mount(this.appElem)
|
this.component = this.app.mount(this.appElem)
|
||||||
|
|
||||||
this.appendChild(this.appElem)
|
this.appendChild(this.appElem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSubmit = (e) => {
|
||||||
|
if (e.detail.success && e.detail?.formSubmission?.formElement?.id === 'submitters_form') {
|
||||||
|
e.detail.fetchResponse.response.json().then((data) => {
|
||||||
|
this.component.template.submitters = data.submitters
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
disconnectedCallback () {
|
disconnectedCallback () {
|
||||||
|
document.removeEventListener('turbo:submit-end', this.onSubmit)
|
||||||
|
|
||||||
this.app?.unmount()
|
this.app?.unmount()
|
||||||
this.appElem?.remove()
|
this.appElem?.remove()
|
||||||
}
|
}
|
||||||
@@ -130,7 +150,8 @@ safeRegisterElement('import-list', class extends HTMLElement {
|
|||||||
this.app = createApp(ImportList, {
|
this.app = createApp(ImportList, {
|
||||||
template: JSON.parse(this.dataset.template),
|
template: JSON.parse(this.dataset.template),
|
||||||
multitenant: this.dataset.multitenant === 'true',
|
multitenant: this.dataset.multitenant === 'true',
|
||||||
authenticityToken: document.querySelector('meta[name="csrf-token"]')?.content
|
authenticityToken: document.querySelector('meta[name="csrf-token"]')?.content,
|
||||||
|
i18n: JSON.parse(this.dataset.i18n || '{}')
|
||||||
})
|
})
|
||||||
|
|
||||||
this.app.mount(this.appElem)
|
this.app.mount(this.appElem)
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ button[disabled] .enabled {
|
|||||||
.autocomplete {
|
.autocomplete {
|
||||||
background: white;
|
background: white;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
font: 14px/22px "-apple-system", BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
font: 16px/25px "-apple-system", BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@apply border border-base-300 mt-1 rounded-md;
|
@apply border border-base-300 mt-1 rounded-md;
|
||||||
@@ -111,7 +111,7 @@ button[disabled] .enabled {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete > div {
|
.autocomplete > div {
|
||||||
@apply px-2 py-1 font-normal text-sm;
|
@apply px-2 py-1.5 font-normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete .group {
|
.autocomplete .group {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export default class extends HTMLElement {
|
||||||
|
connectedCallback () {
|
||||||
|
this.items.forEach((item) => {
|
||||||
|
item.addEventListener('change', (e) => {
|
||||||
|
this.items.forEach((item) => {
|
||||||
|
item.checked = item === e.target && e.target.checked
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
get items () {
|
||||||
|
return this.querySelectorAll('input[type="checkbox"]')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
export default class extends HTMLElement {
|
||||||
|
connectedCallback () {
|
||||||
|
if (this.target) {
|
||||||
|
this.input.value = this.target.value
|
||||||
|
|
||||||
|
this.target.addEventListener('input', (e) => {
|
||||||
|
this.input.value = e.target.value
|
||||||
|
})
|
||||||
|
|
||||||
|
this.target.addEventListener('linked-input.update', (e) => {
|
||||||
|
this.input.value = e.target.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get input () {
|
||||||
|
return this.querySelector('input')
|
||||||
|
}
|
||||||
|
|
||||||
|
get target () {
|
||||||
|
if (this.dataset.targetId) {
|
||||||
|
const listItem = this.closest('[data-targets="dynamic-list.items"]')
|
||||||
|
|
||||||
|
if (listItem) {
|
||||||
|
return listItem.querySelector(`#${this.dataset.targetId}`)
|
||||||
|
} else {
|
||||||
|
return document.getElementById(this.dataset.targetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ export default class extends HTMLElement {
|
|||||||
|
|
||||||
if (input && item[field]) {
|
if (input && item[field]) {
|
||||||
input.value = item[field]
|
input.value = item[field]
|
||||||
|
input.dispatchEvent(new CustomEvent('linked-input.update', { bubbles: true }))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textarea && item[field]) {
|
if (textarea && item[field]) {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
export default class extends HTMLElement {
|
||||||
|
connectedCallback () {
|
||||||
|
this.input.addEventListener('change', (event) => {
|
||||||
|
if (this.dataset.attribute) {
|
||||||
|
this.target[this.dataset.attribute] = event.target.checked
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.dataset.className) {
|
||||||
|
this.target.classList.toggle(this.dataset.className, event.target.value !== this.dataset.value)
|
||||||
|
if (this.dataset.className === 'hidden' && this.target.tagName === 'INPUT') {
|
||||||
|
this.target.disabled = event.target.value !== this.dataset.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.dataset.attribute === 'disabled') {
|
||||||
|
this.target.value = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
get input () {
|
||||||
|
return this.querySelector('input[type="checkbox"]') || this.querySelector('select')
|
||||||
|
}
|
||||||
|
|
||||||
|
get target () {
|
||||||
|
return document.getElementById(this.dataset.targetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ export default actionable(class extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSubmit = (e) => {
|
onSubmit = (e) => {
|
||||||
if (e.detail.success) {
|
if (e.detail.success && e.detail?.formSubmission?.formElement?.dataset?.closeOnSubmit !== 'false') {
|
||||||
this.close()
|
this.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ safeRegisterElement('submission-form', class extends HTMLElement {
|
|||||||
|
|
||||||
this.app = createApp(Form, {
|
this.app = createApp(Form, {
|
||||||
submitter: JSON.parse(this.dataset.submitter),
|
submitter: JSON.parse(this.dataset.submitter),
|
||||||
|
inviteSubmitters: JSON.parse(this.dataset.inviteSubmitters),
|
||||||
canSendEmail: this.dataset.canSendEmail === 'true',
|
canSendEmail: this.dataset.canSendEmail === 'true',
|
||||||
previousSignatureValue: this.dataset.previousSignatureValue,
|
previousSignatureValue: this.dataset.previousSignatureValue,
|
||||||
goToLast: this.dataset.goToLast === 'true',
|
goToLast: this.dataset.goToLast === 'true',
|
||||||
isDemo: this.dataset.isDemo === 'true',
|
isDemo: this.dataset.isDemo === 'true',
|
||||||
attribution: this.dataset.attribution !== 'false',
|
attribution: this.dataset.attribution !== 'false',
|
||||||
scrollPadding: this.dataset.scrollPadding || '-80px',
|
scrollPadding: this.dataset.scrollPadding || '-80px',
|
||||||
|
language: this.dataset.language,
|
||||||
dryRun: this.dataset.dryRun === 'true',
|
dryRun: this.dataset.dryRun === 'true',
|
||||||
expand: ['true', 'false'].includes(this.dataset.expand) ? this.dataset.expand === 'true' : null,
|
expand: ['true', 'false'].includes(this.dataset.expand) ? this.dataset.expand === 'true' : null,
|
||||||
withSignatureId: this.dataset.withSignatureId === 'true',
|
withSignatureId: this.dataset.withSignatureId === 'true',
|
||||||
|
|||||||
@@ -18,9 +18,15 @@ if (token) {
|
|||||||
transform (payload) {
|
transform (payload) {
|
||||||
payload.body.telemetry = []
|
payload.body.telemetry = []
|
||||||
|
|
||||||
const string = JSON.stringify(payload)
|
if (payload.request.query_string) {
|
||||||
|
payload.request.query_string = ''
|
||||||
|
}
|
||||||
|
|
||||||
return JSON.parse(string.replace(/(\/[des]\/)\w{6}/g, (_, m) => m))
|
if (payload.request.url) {
|
||||||
|
payload.request.url = payload.request.url.replace(/(\/[sdep]\/)(\w{5})[^/]+/, '$1$2')
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload
|
||||||
},
|
},
|
||||||
payload: {
|
payload: {
|
||||||
client: {
|
client: {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
class="field-area flex absolute lg:text-base -outline-offset-1"
|
class="field-area flex absolute lg:text-base -outline-offset-1"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
:style="computedStyle"
|
:style="computedStyle"
|
||||||
:class="{ 'text-[1.6vw] lg:text-base': !textOverflowChars, 'text-[1.0vw] lg:text-xs': textOverflowChars, 'cursor-default': !submittable, 'border border-red-100 bg-red-100 cursor-pointer': submittable, 'border border-red-100': !isActive && submittable, 'bg-opacity-80': !isActive && !isValueSet && submittable, 'field-area-active outline-red-500 outline-dashed outline-2 z-10': isActive && submittable, 'bg-opacity-40': (isActive || isValueSet) && submittable }"
|
:class="{ 'font-serif': field.preferences?.font === 'Times', 'text-[1.6vw] lg:text-base': !textOverflowChars, 'text-[1.0vw] lg:text-xs': textOverflowChars, 'cursor-default': !submittable, 'border border-red-100 bg-red-100 cursor-pointer': submittable, 'border border-red-100': !isActive && submittable, 'bg-opacity-80': !isActive && !isValueSet && submittable, 'field-area-active outline-red-500 outline-dashed outline-2 z-10': isActive && submittable, 'bg-opacity-40': (isActive || isValueSet) && submittable }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="(!withFieldPlaceholder || !field.name || field.type === 'cells') && !isActive && !isValueSet && field.type !== 'checkbox' && submittable && !area.option_uuid"
|
v-if="(!withFieldPlaceholder || !field.name || field.type === 'cells') && !isActive && !isValueSet && field.type !== 'checkbox' && submittable && !area.option_uuid"
|
||||||
@@ -29,12 +29,12 @@
|
|||||||
{{ optionValue(option) }}
|
{{ optionValue(option) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ field.name || fieldNames[field.type] }}
|
{{ field.title || field.name || fieldNames[field.type] }}
|
||||||
<template v-if="field.type === 'checkbox' && !field.name">
|
<template v-if="field.type === 'checkbox' && !field.name">
|
||||||
{{ fieldIndex + 1 }}
|
{{ fieldIndex + 1 }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="!field.required && field.type !== 'checkbox'">
|
<template v-else-if="!field.required && field.type !== 'checkbox'">
|
||||||
(optional)
|
({{ t('optional') }})
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -226,7 +226,8 @@ export default {
|
|||||||
},
|
},
|
||||||
submitter: {
|
submitter: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: false,
|
||||||
|
default: () => ({})
|
||||||
},
|
},
|
||||||
withSignatureId: {
|
withSignatureId: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
|||||||
@@ -21,14 +21,14 @@
|
|||||||
:values="values"
|
:values="values"
|
||||||
:field="field"
|
:field="field"
|
||||||
:area="area"
|
:area="area"
|
||||||
:submittable="true"
|
:submittable="submittable"
|
||||||
:field-index="fieldIndex"
|
:field-index="fieldIndex"
|
||||||
:scroll-padding="scrollPadding"
|
:scroll-padding="scrollPadding"
|
||||||
:submitter="submitter"
|
:submitter="submitter"
|
||||||
:with-field-placeholder="withFieldPlaceholder"
|
:with-field-placeholder="withFieldPlaceholder"
|
||||||
:with-signature-id="withSignatureId"
|
:with-signature-id="withSignatureId"
|
||||||
:is-active="currentStep === step"
|
:is-active="currentStep === step"
|
||||||
:with-label="withLabel && !withFieldPlaceholder"
|
:with-label="withLabel && !withFieldPlaceholder && step.length < 2"
|
||||||
:is-value-set="step.some((f) => f.uuid in values)"
|
:is-value-set="step.some((f) => f.uuid in values)"
|
||||||
:attachments-index="attachmentsIndex"
|
:attachments-index="attachmentsIndex"
|
||||||
@click="$emit('focus-step', stepIndex)"
|
@click="$emit('focus-step', stepIndex)"
|
||||||
@@ -58,6 +58,11 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
submittable: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
submitter: {
|
submitter: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
@@ -127,10 +132,18 @@ export default {
|
|||||||
this.scrollInContainer(areaRef.$el)
|
this.scrollInContainer(areaRef.$el)
|
||||||
} else {
|
} else {
|
||||||
const targetRect = areaRef.$refs.scrollToElem.getBoundingClientRect()
|
const targetRect = areaRef.$refs.scrollToElem.getBoundingClientRect()
|
||||||
const root = this.$root.$el?.parentNode?.classList?.contains('ds') ? this.$root.$el : document.body
|
|
||||||
const rootRect = root.getBoundingClientRect()
|
|
||||||
const scrollEl = this.scrollEl || window
|
const scrollEl = this.scrollEl || window
|
||||||
|
|
||||||
|
let rootRect = {}
|
||||||
|
|
||||||
|
if (this.scrollEl === document.documentElement) {
|
||||||
|
rootRect = this.scrollEl.getBoundingClientRect()
|
||||||
|
} else {
|
||||||
|
const root = this.$root.$el?.parentNode?.classList?.contains('ds') ? this.$root.$el : document.body
|
||||||
|
|
||||||
|
rootRect = root.getBoundingClientRect()
|
||||||
|
}
|
||||||
|
|
||||||
scrollEl.scrollTo({ top: targetRect.top - rootRect.top, behavior: 'smooth' })
|
scrollEl.scrollTo({ top: targetRect.top - rootRect.top, behavior: 'smooth' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
id="form_completed"
|
||||||
class="mx-auto max-w-md flex flex-col"
|
class="mx-auto max-w-md flex flex-col"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
>
|
>
|
||||||
@@ -10,7 +11,7 @@
|
|||||||
:height="30"
|
:height="30"
|
||||||
/>
|
/>
|
||||||
<span>
|
<span>
|
||||||
{{ completedMessage.title || t('form_has_been_completed') }}
|
{{ completedMessage.title || (hasSignatureFields ? (hasMultipleDocuments ? t('documents_have_been_signed') : t('document_has_been_signed')) : t('form_has_been_completed')) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -88,7 +89,7 @@
|
|||||||
v-if="attribution"
|
v-if="attribution"
|
||||||
class="text-center mt-4"
|
class="text-center mt-4"
|
||||||
>
|
>
|
||||||
{{ t('signed_with') }}
|
{{ t('powered_by') }}
|
||||||
<a
|
<a
|
||||||
href="https://www.docuseal.co/start"
|
href="https://www.docuseal.co/start"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -129,6 +130,16 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
hasSignatureFields: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasMultipleDocuments: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
withDownloadButton: {
|
withDownloadButton: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -181,6 +192,10 @@ export default {
|
|||||||
spread: 140
|
spread: 140
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window.decline_button) {
|
||||||
|
window.decline_button.setAttribute('disabled', 'true')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
sendCopyToEmail () {
|
sendCopyToEmail () {
|
||||||
@@ -208,7 +223,7 @@ export default {
|
|||||||
this.downloadUrls(urls)
|
this.downloadUrls(urls)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
alert('Failed to download files')
|
alert(this.t('failed_to_download_files'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
:scroll-padding="scrollPadding"
|
:scroll-padding="scrollPadding"
|
||||||
@focus-step="[saveStep(), currentField.type !== 'checkbox' ? isFormVisible = true : '', goToStep($event, false, true)]"
|
@focus-step="[saveStep(), currentField.type !== 'checkbox' ? isFormVisible = true : '', goToStep($event, false, true)]"
|
||||||
/>
|
/>
|
||||||
|
<FieldAreas
|
||||||
|
:steps="readonlyConditionalFields.map((e) => [e])"
|
||||||
|
:values="readonlyConditionalFields.reduce((acc, f) => { acc[f.uuid] = f.default_value; return acc }, {})"
|
||||||
|
:submitter="submitter"
|
||||||
|
:submittable="false"
|
||||||
|
/>
|
||||||
<FormulaFieldAreas
|
<FormulaFieldAreas
|
||||||
v-if="formulaFields.length"
|
v-if="formulaFields.length"
|
||||||
:fields="formulaFields"
|
:fields="formulaFields"
|
||||||
@@ -32,8 +38,11 @@
|
|||||||
<template v-else-if="alwaysMinimize">
|
<template v-else-if="alwaysMinimize">
|
||||||
{{ t('next') }}
|
{{ t('next') }}
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="isShowContinue">
|
||||||
|
{{ t('continue') }}
|
||||||
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ t('submit_form') }}
|
{{ t('start_now') }}
|
||||||
</template>
|
</template>
|
||||||
<IconArrowsDiagonal
|
<IconArrowsDiagonal
|
||||||
class="absolute right-0 mr-4"
|
class="absolute right-0 mr-4"
|
||||||
@@ -53,7 +62,7 @@
|
|||||||
id="minimize_form_button"
|
id="minimize_form_button"
|
||||||
class="absolute right-0 mr-2 mt-2 top-0 hidden md:block"
|
class="absolute right-0 mr-2 mt-2 top-0 hidden md:block"
|
||||||
:title="t('minimize')"
|
:title="t('minimize')"
|
||||||
@click.prevent="isFormVisible = false"
|
@click.prevent="minimizeForm"
|
||||||
>
|
>
|
||||||
<IconArrowsDiagonalMinimize2
|
<IconArrowsDiagonalMinimize2
|
||||||
:width="20"
|
:width="20"
|
||||||
@@ -64,7 +73,7 @@
|
|||||||
:class="{ 'md:px-4': isBreakpointMd }"
|
:class="{ 'md:px-4': isBreakpointMd }"
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
v-if="!isCompleted"
|
v-if="!isCompleted && !isInvite"
|
||||||
ref="form"
|
ref="form"
|
||||||
:action="submitPath"
|
:action="submitPath"
|
||||||
method="post"
|
method="post"
|
||||||
@@ -195,7 +204,7 @@
|
|||||||
<span
|
<span
|
||||||
@click="scrollIntoField(currentField)"
|
@click="scrollIntoField(currentField)"
|
||||||
>
|
>
|
||||||
{{ t('complete_hightlighted_checkboxes_and_click') }} <span class="font-semibold">{{ stepFields.length === currentStep + 1 ? t('submit') : t('next') }}</span>.
|
{{ t('complete_hightlighted_checkboxes_and_click') }} <span class="font-semibold">{{ submitButtonText }}</span>.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -259,7 +268,7 @@
|
|||||||
>
|
>
|
||||||
<template v-if="isAnonymousChecboxes || !showFieldNames">
|
<template v-if="isAnonymousChecboxes || !showFieldNames">
|
||||||
<span class="text-xl">
|
<span class="text-xl">
|
||||||
{{ t('complete_hightlighted_checkboxes_and_click') }} <span class="font-semibold">{{ stepFields.length === currentStep + 1 ? t('submit') : t('next') }}</span>.
|
{{ t('complete_hightlighted_checkboxes_and_click') }} <span class="font-semibold">{{ submitButtonText }}</span>.
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
v-for="field in currentStepFields"
|
v-for="field in currentStepFields"
|
||||||
@@ -334,7 +343,7 @@
|
|||||||
:remember-signature="rememberSignature"
|
:remember-signature="rememberSignature"
|
||||||
:attachments-index="attachmentsIndex"
|
:attachments-index="attachmentsIndex"
|
||||||
:require-signing-reason="requireSigningReason"
|
:require-signing-reason="requireSigningReason"
|
||||||
:button-text="buttonText"
|
:button-text="submitButtonText"
|
||||||
:dry-run="dryRun"
|
:dry-run="dryRun"
|
||||||
:with-disclosure="withDisclosure"
|
:with-disclosure="withDisclosure"
|
||||||
:with-qr-button="withQrButton"
|
:with-qr-button="withQrButton"
|
||||||
@@ -343,7 +352,7 @@
|
|||||||
@update:reason="values[currentField.preferences?.reason_field_uuid] = $event"
|
@update:reason="values[currentField.preferences?.reason_field_uuid] = $event"
|
||||||
@attached="attachments.push($event)"
|
@attached="attachments.push($event)"
|
||||||
@start="scrollIntoField(currentField)"
|
@start="scrollIntoField(currentField)"
|
||||||
@minimize="isFormVisible = false"
|
@minimize="minimizeForm"
|
||||||
/>
|
/>
|
||||||
<InitialsStep
|
<InitialsStep
|
||||||
v-else-if="currentField.type === 'initials'"
|
v-else-if="currentField.type === 'initials'"
|
||||||
@@ -359,7 +368,7 @@
|
|||||||
@attached="attachments.push($event)"
|
@attached="attachments.push($event)"
|
||||||
@start="scrollIntoField(currentField)"
|
@start="scrollIntoField(currentField)"
|
||||||
@focus="scrollIntoField(currentField)"
|
@focus="scrollIntoField(currentField)"
|
||||||
@minimize="isFormVisible = false"
|
@minimize="minimizeForm"
|
||||||
/>
|
/>
|
||||||
<AttachmentStep
|
<AttachmentStep
|
||||||
v-else-if="currentField.type === 'file'"
|
v-else-if="currentField.type === 'file'"
|
||||||
@@ -415,7 +424,7 @@
|
|||||||
class="mr-1 animate-spin"
|
class="mr-1 animate-spin"
|
||||||
/>
|
/>
|
||||||
<span>
|
<span>
|
||||||
{{ buttonText }}
|
{{ submitButtonText }}
|
||||||
</span><span
|
</span><span
|
||||||
v-if="isSubmitting"
|
v-if="isSubmitting"
|
||||||
class="w-6 flex justify-start mr-1"
|
class="w-6 flex justify-start mr-1"
|
||||||
@@ -430,10 +439,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<InviteForm
|
||||||
|
v-else-if="isInvite"
|
||||||
|
:submitters="inviteSubmitters"
|
||||||
|
:submitter-slug="submitterSlug"
|
||||||
|
:authenticity-token="authenticityToken"
|
||||||
|
:url="baseUrl + submitPath + '/invite'"
|
||||||
|
:style="{ maxWidth: isBreakpointMd ? '582px' : '' }"
|
||||||
|
@success="[isInvite = false, performComplete($event)]"
|
||||||
|
/>
|
||||||
<FormCompleted
|
<FormCompleted
|
||||||
v-else
|
v-else
|
||||||
:is-demo="isDemo"
|
:is-demo="isDemo"
|
||||||
:attribution="attribution"
|
:attribution="attribution"
|
||||||
|
:has-signature-fields="stepFields.some((fields) => fields.some((f) => ['signature', 'initials'].includes(f.type)))"
|
||||||
|
:has-multiple-documents="hasMultipleDocuments"
|
||||||
:completed-button="completedRedirectUrl ? {} : completedButton"
|
:completed-button="completedRedirectUrl ? {} : completedButton"
|
||||||
:completed-message="completedRedirectUrl ? {} : completedMessage"
|
:completed-message="completedRedirectUrl ? {} : completedMessage"
|
||||||
:with-send-copy-button="withSendCopyButton && !completedRedirectUrl"
|
:with-send-copy-button="withSendCopyButton && !completedRedirectUrl"
|
||||||
@@ -479,6 +499,7 @@ import TextStep from './text_step'
|
|||||||
import NumberStep from './number_step'
|
import NumberStep from './number_step'
|
||||||
import DateStep from './date_step'
|
import DateStep from './date_step'
|
||||||
import MarkdownContent from './markdown_content'
|
import MarkdownContent from './markdown_content'
|
||||||
|
import InviteForm from './invite_form'
|
||||||
import FormCompleted from './completed'
|
import FormCompleted from './completed'
|
||||||
import { IconInnerShadowTop, IconArrowsDiagonal, IconWritingSign, IconArrowsDiagonalMinimize2 } from '@tabler/icons-vue'
|
import { IconInnerShadowTop, IconArrowsDiagonal, IconWritingSign, IconArrowsDiagonalMinimize2 } from '@tabler/icons-vue'
|
||||||
import AppearsOn from './appears_on'
|
import AppearsOn from './appears_on'
|
||||||
@@ -516,6 +537,7 @@ export default {
|
|||||||
IconWritingSign,
|
IconWritingSign,
|
||||||
AttachmentStep,
|
AttachmentStep,
|
||||||
InitialsStep,
|
InitialsStep,
|
||||||
|
InviteForm,
|
||||||
MultiSelectStep,
|
MultiSelectStep,
|
||||||
IconInnerShadowTop,
|
IconInnerShadowTop,
|
||||||
DateStep,
|
DateStep,
|
||||||
@@ -542,6 +564,11 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
inviteSubmitters: {
|
||||||
|
type: Array,
|
||||||
|
required: false,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
withSignatureId: {
|
withSignatureId: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -733,9 +760,11 @@ export default {
|
|||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isCompleted: false,
|
isCompleted: false,
|
||||||
|
isInvite: false,
|
||||||
isFormVisible: this.expand !== false,
|
isFormVisible: this.expand !== false,
|
||||||
showFillAllRequiredFields: false,
|
showFillAllRequiredFields: false,
|
||||||
currentStep: 0,
|
currentStep: 0,
|
||||||
|
isShowContinue: false,
|
||||||
enableScrollIntoField: true,
|
enableScrollIntoField: true,
|
||||||
phoneVerifiedValues: {},
|
phoneVerifiedValues: {},
|
||||||
orientation: screen?.orientation?.type,
|
orientation: screen?.orientation?.type,
|
||||||
@@ -748,9 +777,15 @@ export default {
|
|||||||
isMobile () {
|
isMobile () {
|
||||||
return /android|iphone|ipad/i.test(navigator.userAgent)
|
return /android|iphone|ipad/i.test(navigator.userAgent)
|
||||||
},
|
},
|
||||||
buttonText () {
|
submitButtonText () {
|
||||||
if (this.alwaysMinimize || this.stepFields.length === this.currentStep + 1) {
|
if (this.alwaysMinimize) {
|
||||||
return this.t('submit')
|
return this.t('submit')
|
||||||
|
} else if (this.stepFields.length === this.currentStep + 1) {
|
||||||
|
if (this.currentField.type === 'signature') {
|
||||||
|
return this.t('sign_and_complete')
|
||||||
|
} else {
|
||||||
|
return this.t('complete')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return this.t('next')
|
return this.t('next')
|
||||||
}
|
}
|
||||||
@@ -758,6 +793,18 @@ export default {
|
|||||||
alwaysMinimize () {
|
alwaysMinimize () {
|
||||||
return this.minimize || (this.orientation?.includes('landscape') && this.isMobile && parseInt(window.innerHeight) < 550)
|
return this.minimize || (this.orientation?.includes('landscape') && this.isMobile && parseInt(window.innerHeight) < 550)
|
||||||
},
|
},
|
||||||
|
hasMultipleDocuments () {
|
||||||
|
return Object.keys(
|
||||||
|
this.stepFields.reduce((acc, fields) => {
|
||||||
|
fields.forEach((f) => {
|
||||||
|
f.areas?.forEach((a) => {
|
||||||
|
acc[a.attachment_uuid] = 1
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
).filter(Boolean).length > 1
|
||||||
|
},
|
||||||
currentStepFields () {
|
currentStepFields () {
|
||||||
return this.stepFields[this.currentStep] || []
|
return this.stepFields[this.currentStep] || []
|
||||||
},
|
},
|
||||||
@@ -802,6 +849,9 @@ export default {
|
|||||||
currentField () {
|
currentField () {
|
||||||
return this.currentStepFields[0]
|
return this.currentStepFields[0]
|
||||||
},
|
},
|
||||||
|
readonlyConditionalFields () {
|
||||||
|
return this.fields.filter((f) => f.readonly && f.conditions?.length && this.checkFieldConditions(f))
|
||||||
|
},
|
||||||
stepFields () {
|
stepFields () {
|
||||||
return this.fields.filter((f) => !f.readonly).reduce((acc, f) => {
|
return this.fields.filter((f) => !f.readonly).reduce((acc, f) => {
|
||||||
const prevStep = acc[acc.length - 1]
|
const prevStep = acc[acc.length - 1]
|
||||||
@@ -847,7 +897,7 @@ export default {
|
|||||||
mounted () {
|
mounted () {
|
||||||
this.submittedValues = JSON.parse(JSON.stringify(this.values))
|
this.submittedValues = JSON.parse(JSON.stringify(this.values))
|
||||||
|
|
||||||
screen?.orientation.addEventListener('change', this.onOrientationChange)
|
screen?.orientation?.addEventListener('change', this.onOrientationChange)
|
||||||
|
|
||||||
this.fields.forEach((field) => {
|
this.fields.forEach((field) => {
|
||||||
if (field.default_value && !field.readonly) {
|
if (field.default_value && !field.readonly) {
|
||||||
@@ -879,11 +929,11 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (document.body?.clientWidth >= 768 && this.expand !== true && ['signature', 'initials', 'file', 'image'].includes(this.currentField?.type)) {
|
if (document.body?.clientWidth >= 768 && this.expand !== true && ['signature', 'initials', 'file', 'image'].includes(this.currentField?.type)) {
|
||||||
this.isFormVisible = false
|
this.minimizeForm()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.alwaysMinimize) {
|
if (this.alwaysMinimize) {
|
||||||
this.isFormVisible = false
|
this.minimizeForm()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
|
if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
|
||||||
@@ -933,12 +983,12 @@ export default {
|
|||||||
return acc && isEmpty(this.values[c.field_uuid])
|
return acc && isEmpty(this.values[c.field_uuid])
|
||||||
} else if (['not_empty', 'checked'].includes(c.action)) {
|
} else if (['not_empty', 'checked'].includes(c.action)) {
|
||||||
return acc && !isEmpty(this.values[c.field_uuid])
|
return acc && !isEmpty(this.values[c.field_uuid])
|
||||||
} else if (['equal', 'contains'].includes(c.action)) {
|
} else if (['equal', 'contains'].includes(c.action) && field) {
|
||||||
const option = field.options.find((o) => o.uuid === c.value)
|
const option = field.options.find((o) => o.uuid === c.value)
|
||||||
const values = [this.values[c.field_uuid]].flat()
|
const values = [this.values[c.field_uuid]].flat()
|
||||||
|
|
||||||
return acc && values.includes(this.optionValue(option, field.options.indexOf(option)))
|
return acc && values.includes(this.optionValue(option, field.options.indexOf(option)))
|
||||||
} else if (['not_equal', 'does_not_contain'].includes(c.action)) {
|
} else if (['not_equal', 'does_not_contain'].includes(c.action) && field) {
|
||||||
const option = field.options.find((o) => o.uuid === c.value)
|
const option = field.options.find((o) => o.uuid === c.value)
|
||||||
const values = [this.values[c.field_uuid]].flat()
|
const values = [this.values[c.field_uuid]].flat()
|
||||||
|
|
||||||
@@ -1110,7 +1160,7 @@ export default {
|
|||||||
const formData = new FormData(this.$refs.form)
|
const formData = new FormData(this.$refs.form)
|
||||||
const isLastStep = this.currentStep === this.stepFields.length - 1
|
const isLastStep = this.currentStep === this.stepFields.length - 1
|
||||||
|
|
||||||
if (isLastStep && !emptyRequiredField) {
|
if (isLastStep && !emptyRequiredField && !this.inviteSubmitters.length) {
|
||||||
formData.append('completed', 'true')
|
formData.append('completed', 'true')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1133,15 +1183,11 @@ export default {
|
|||||||
return Promise.reject(new Error(data.error))
|
return Promise.reject(new Error(data.error))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLastStep) {
|
|
||||||
this.isSecondWalkthrough = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextStep = (isLastStep && emptyRequiredField) || this.stepFields[this.currentStep + 1]
|
const nextStep = (isLastStep && emptyRequiredField) || this.stepFields[this.currentStep + 1]
|
||||||
|
|
||||||
if (nextStep) {
|
if (nextStep) {
|
||||||
if (this.alwaysMinimize) {
|
if (this.alwaysMinimize) {
|
||||||
this.isFormVisible = false
|
this.minimizeForm()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.goToStep(this.stepFields.indexOf(nextStep), this.autoscrollFields)
|
this.goToStep(this.stepFields.indexOf(nextStep), this.autoscrollFields)
|
||||||
@@ -1149,18 +1195,10 @@ export default {
|
|||||||
if (emptyRequiredField === nextStep) {
|
if (emptyRequiredField === nextStep) {
|
||||||
this.showFillAllRequiredFields = true
|
this.showFillAllRequiredFields = true
|
||||||
}
|
}
|
||||||
|
} else if (this.inviteSubmitters.length) {
|
||||||
|
this.isInvite = true
|
||||||
} else {
|
} else {
|
||||||
this.isCompleted = true
|
this.performComplete(response)
|
||||||
|
|
||||||
const respData = await response.text()
|
|
||||||
|
|
||||||
if (respData) {
|
|
||||||
this.onComplete(JSON.parse(respData))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.completedRedirectUrl) {
|
|
||||||
window.location.href = this.completedRedirectUrl
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@@ -1169,13 +1207,32 @@ export default {
|
|||||||
})
|
})
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
if (error?.message === 'Image too small') {
|
if (error?.message === 'Image too small') {
|
||||||
alert('Signature is too small - please redraw.')
|
alert(this.t('signature_is_too_small_please_redraw'))
|
||||||
} else {
|
} else {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.isSubmitting = false
|
this.isSubmitting = false
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
minimizeForm () {
|
||||||
|
this.isFormVisible = false
|
||||||
|
this.isShowContinue = true
|
||||||
|
},
|
||||||
|
async performComplete (resp) {
|
||||||
|
this.isCompleted = true
|
||||||
|
|
||||||
|
if (resp?.text) {
|
||||||
|
const respData = await resp.text()
|
||||||
|
|
||||||
|
if (respData) {
|
||||||
|
this.onComplete(JSON.parse(respData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.completedRedirectUrl) {
|
||||||
|
window.location.href = this.completedRedirectUrl
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
const en = {
|
const en = {
|
||||||
|
complete: 'Complete',
|
||||||
|
sign_and_complete: 'Sign and Complete',
|
||||||
text: 'Text',
|
text: 'Text',
|
||||||
by_clicking_you_agree_to_the: 'By clicking "{button}", you agree to the',
|
by_clicking_you_agree_to_the: 'By clicking "{button}", you agree to the',
|
||||||
electronic_signature_disclosure: 'Electronic Signature Disclosure',
|
electronic_signature_disclosure: 'Electronic Signature Disclosure',
|
||||||
@@ -10,6 +12,8 @@ const en = {
|
|||||||
reviewed: 'Reviewed',
|
reviewed: 'Reviewed',
|
||||||
other: 'Other',
|
other: 'Other',
|
||||||
authored_by_me: 'Authored by me',
|
authored_by_me: 'Authored by me',
|
||||||
|
invite: 'Invite',
|
||||||
|
email: 'Email',
|
||||||
approved_by: 'Approved by',
|
approved_by: 'Approved by',
|
||||||
reviewed_by: 'Reviewed by',
|
reviewed_by: 'Reviewed by',
|
||||||
authored_by: 'Authored by',
|
authored_by: 'Authored by',
|
||||||
@@ -36,7 +40,8 @@ const en = {
|
|||||||
minimize: 'Minimize',
|
minimize: 'Minimize',
|
||||||
payment: 'Payment',
|
payment: 'Payment',
|
||||||
phone: 'Phone',
|
phone: 'Phone',
|
||||||
submit_form: 'Submit Form',
|
start_now: 'Start Now',
|
||||||
|
continue: 'Continue',
|
||||||
sign_now: 'Sign Now',
|
sign_now: 'Sign Now',
|
||||||
type_here_: 'Type here...',
|
type_here_: 'Type here...',
|
||||||
optional: 'optional',
|
optional: 'optional',
|
||||||
@@ -57,8 +62,10 @@ const en = {
|
|||||||
type_signature_here: 'Type signature here',
|
type_signature_here: 'Type signature here',
|
||||||
type_initial_here: 'Type initials here',
|
type_initial_here: 'Type initials here',
|
||||||
form_has_been_completed: 'Form has been completed!',
|
form_has_been_completed: 'Form has been completed!',
|
||||||
|
document_has_been_signed: 'Document has been signed!',
|
||||||
|
documents_have_been_signed: 'Documents have been signed!',
|
||||||
create_a_free_account: 'Create a Free Account',
|
create_a_free_account: 'Create a Free Account',
|
||||||
signed_with: 'Signed with',
|
powered_by: 'Powered by',
|
||||||
please_check_the_box_to_continue: 'Please check the box to continue',
|
please_check_the_box_to_continue: 'Please check the box to continue',
|
||||||
open_source_documents_software: 'open source documents software',
|
open_source_documents_software: 'open source documents software',
|
||||||
verified_phone_number: 'Verify Phone Number',
|
verified_phone_number: 'Verify Phone Number',
|
||||||
@@ -85,6 +92,10 @@ const en = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const es = {
|
const es = {
|
||||||
|
complete: 'Completar',
|
||||||
|
sign_and_complete: 'Firmar y Completar',
|
||||||
|
invite: 'Invitar',
|
||||||
|
email: 'Correo electrónico',
|
||||||
approved: 'Aprobado',
|
approved: 'Aprobado',
|
||||||
reviewed: 'Revisado',
|
reviewed: 'Revisado',
|
||||||
other: 'Otro',
|
other: 'Otro',
|
||||||
@@ -122,7 +133,8 @@ const es = {
|
|||||||
payment: 'Pago',
|
payment: 'Pago',
|
||||||
phone: 'Teléfono',
|
phone: 'Teléfono',
|
||||||
take_photo: 'Tomar foto',
|
take_photo: 'Tomar foto',
|
||||||
submit_form: 'Enviar Formulario',
|
start_now: 'Comenzar ahora',
|
||||||
|
continue: 'Continuar',
|
||||||
sign_now: 'Firmar ahora',
|
sign_now: 'Firmar ahora',
|
||||||
type_here_: 'Escribe aquí...',
|
type_here_: 'Escribe aquí...',
|
||||||
optional: 'opcional',
|
optional: 'opcional',
|
||||||
@@ -142,8 +154,10 @@ const es = {
|
|||||||
type_signature_here: 'Escribe la firma aquí',
|
type_signature_here: 'Escribe la firma aquí',
|
||||||
type_initial_here: 'Escribe las iniciales aquí',
|
type_initial_here: 'Escribe las iniciales aquí',
|
||||||
form_has_been_completed: '¡El formulario ha sido completado!',
|
form_has_been_completed: '¡El formulario ha sido completado!',
|
||||||
|
document_has_been_signed: '¡El documento ha sido firmado!',
|
||||||
|
documents_have_been_signed: '¡Los documentos han sido firmados!',
|
||||||
create_a_free_account: 'Crear una Cuenta Gratuita',
|
create_a_free_account: 'Crear una Cuenta Gratuita',
|
||||||
signed_with: 'Firmado con',
|
powered_by: 'Desarrollado por',
|
||||||
please_check_the_box_to_continue: 'Por favor marque la casilla para continuar',
|
please_check_the_box_to_continue: 'Por favor marque la casilla para continuar',
|
||||||
open_source_documents_software: 'software de documentos de código abierto',
|
open_source_documents_software: 'software de documentos de código abierto',
|
||||||
verified_phone_number: 'Verificar número de teléfono',
|
verified_phone_number: 'Verificar número de teléfono',
|
||||||
@@ -170,6 +184,10 @@ const es = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const it = {
|
const it = {
|
||||||
|
complete: 'Completa',
|
||||||
|
sign_and_complete: 'Firma e Completa',
|
||||||
|
invite: 'Invita',
|
||||||
|
email: 'Email',
|
||||||
approved: 'Approvato',
|
approved: 'Approvato',
|
||||||
reviewed: 'Revisionato',
|
reviewed: 'Revisionato',
|
||||||
other: 'Altro',
|
other: 'Altro',
|
||||||
@@ -198,7 +216,7 @@ const it = {
|
|||||||
pay: 'Pagamento',
|
pay: 'Pagamento',
|
||||||
file: 'File',
|
file: 'File',
|
||||||
select: 'Seleziona',
|
select: 'Seleziona',
|
||||||
checkbox: 'Casella di controllo',
|
checkbox: 'Checkbox',
|
||||||
multiple: 'Multiplo',
|
multiple: 'Multiplo',
|
||||||
radio: 'Radio',
|
radio: 'Radio',
|
||||||
cells: 'Celle',
|
cells: 'Celle',
|
||||||
@@ -206,7 +224,8 @@ const it = {
|
|||||||
payment: 'Pagamento',
|
payment: 'Pagamento',
|
||||||
number_phone_is_invalid: '{number} telefono non è valido',
|
number_phone_is_invalid: '{number} telefono non è valido',
|
||||||
phone: 'Telefono',
|
phone: 'Telefono',
|
||||||
submit_form: 'Invia Modulo',
|
start_now: 'Inizia ora',
|
||||||
|
continue: 'Continua',
|
||||||
sign_now: 'Firma ora',
|
sign_now: 'Firma ora',
|
||||||
type_here_: 'Digita qui...',
|
type_here_: 'Digita qui...',
|
||||||
optional: 'opzionale',
|
optional: 'opzionale',
|
||||||
@@ -227,8 +246,10 @@ const it = {
|
|||||||
type_signature_here: 'Scrivi la firma qui',
|
type_signature_here: 'Scrivi la firma qui',
|
||||||
type_initial_here: 'Scrivi le iniziali qui',
|
type_initial_here: 'Scrivi le iniziali qui',
|
||||||
form_has_been_completed: 'Il modulo è stato completato!',
|
form_has_been_completed: 'Il modulo è stato completato!',
|
||||||
|
document_has_been_signed: 'Il documento è stato firmato!',
|
||||||
|
documents_have_been_signed: 'I documenti sono stati firmati!',
|
||||||
create_a_free_account: 'Crea un Account Gratuito',
|
create_a_free_account: 'Crea un Account Gratuito',
|
||||||
signed_with: 'Firmato con',
|
powered_by: 'Desarrollado por',
|
||||||
please_check_the_box_to_continue: 'Si prega di spuntare la casella per continuare',
|
please_check_the_box_to_continue: 'Si prega di spuntare la casella per continuare',
|
||||||
open_source_documents_software: 'software di documenti open source',
|
open_source_documents_software: 'software di documenti open source',
|
||||||
verified_phone_number: 'Verifica numero di telefono',
|
verified_phone_number: 'Verifica numero di telefono',
|
||||||
@@ -255,6 +276,10 @@ const it = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const de = {
|
const de = {
|
||||||
|
complete: 'Abschließen',
|
||||||
|
sign_and_complete: 'Signieren und Abschließen',
|
||||||
|
invite: 'Einladen',
|
||||||
|
email: 'E-Mail',
|
||||||
approved: 'Genehmigt',
|
approved: 'Genehmigt',
|
||||||
reviewed: 'Überprüft',
|
reviewed: 'Überprüft',
|
||||||
other: 'Andere',
|
other: 'Andere',
|
||||||
@@ -291,7 +316,8 @@ const de = {
|
|||||||
payment: 'Zahlung',
|
payment: 'Zahlung',
|
||||||
number_phone_is_invalid: '{number} Telefonnummer ist ungültig',
|
number_phone_is_invalid: '{number} Telefonnummer ist ungültig',
|
||||||
phone: 'Telefon',
|
phone: 'Telefon',
|
||||||
submit_form: 'Formular absenden',
|
start_now: 'Jetzt starten',
|
||||||
|
continue: 'Fortsetzen',
|
||||||
sign_now: 'Jetzt unterschreiben',
|
sign_now: 'Jetzt unterschreiben',
|
||||||
type_here_: 'Hier eingeben...',
|
type_here_: 'Hier eingeben...',
|
||||||
optional: 'optional',
|
optional: 'optional',
|
||||||
@@ -312,8 +338,10 @@ const de = {
|
|||||||
type_signature_here: 'Unterschrift hier eingeben',
|
type_signature_here: 'Unterschrift hier eingeben',
|
||||||
type_initial_here: 'Initialen hier eingeben',
|
type_initial_here: 'Initialen hier eingeben',
|
||||||
form_has_been_completed: 'Formular wurde ausgefüllt!',
|
form_has_been_completed: 'Formular wurde ausgefüllt!',
|
||||||
|
document_has_been_signed: 'Dokument wurde unterschrieben!',
|
||||||
|
documents_have_been_signed: 'Dokumente wurden unterschrieben!',
|
||||||
create_a_free_account: 'Kostenloses Konto erstellen',
|
create_a_free_account: 'Kostenloses Konto erstellen',
|
||||||
signed_with: 'Unterschrieben mit',
|
powered_by: 'Bereitgestellt von',
|
||||||
please_check_the_box_to_continue: 'Bitte setzen Sie das Häkchen, um fortzufahren',
|
please_check_the_box_to_continue: 'Bitte setzen Sie das Häkchen, um fortzufahren',
|
||||||
open_source_documents_software: 'Open-Source-Dokumentensoftware',
|
open_source_documents_software: 'Open-Source-Dokumentensoftware',
|
||||||
verified_phone_number: 'Telefonnummer überprüfen',
|
verified_phone_number: 'Telefonnummer überprüfen',
|
||||||
@@ -340,6 +368,10 @@ const de = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fr = {
|
const fr = {
|
||||||
|
complete: 'Terminer',
|
||||||
|
sign_and_complete: 'Signer et Terminer',
|
||||||
|
invite: 'Inviter',
|
||||||
|
email: 'Courriel',
|
||||||
approved: 'Approuvé',
|
approved: 'Approuvé',
|
||||||
reviewed: 'Révisé',
|
reviewed: 'Révisé',
|
||||||
other: 'Autre',
|
other: 'Autre',
|
||||||
@@ -376,7 +408,8 @@ const fr = {
|
|||||||
payment: 'Paiement',
|
payment: 'Paiement',
|
||||||
number_phone_is_invalid: '{number} téléphone est invalide',
|
number_phone_is_invalid: '{number} téléphone est invalide',
|
||||||
phone: 'Téléphone',
|
phone: 'Téléphone',
|
||||||
submit_form: 'Envoyer le Formulaire',
|
start_now: 'Commencer maintenant',
|
||||||
|
continue: 'Continuer',
|
||||||
sign_now: 'Signer maintenant',
|
sign_now: 'Signer maintenant',
|
||||||
type_here_: 'Tapez ici...',
|
type_here_: 'Tapez ici...',
|
||||||
optional: 'facultatif',
|
optional: 'facultatif',
|
||||||
@@ -397,8 +430,10 @@ const fr = {
|
|||||||
type_signature_here: 'Tapez la signature ici',
|
type_signature_here: 'Tapez la signature ici',
|
||||||
type_initial_here: 'Tapez les initiales ici',
|
type_initial_here: 'Tapez les initiales ici',
|
||||||
form_has_been_completed: 'Le formulaire a été complété !',
|
form_has_been_completed: 'Le formulaire a été complété !',
|
||||||
|
document_has_been_signed: 'Le document a été signé!',
|
||||||
|
documents_have_been_signed: 'Les documents ont été signés!',
|
||||||
create_a_free_account: 'Créer un Compte Gratuit',
|
create_a_free_account: 'Créer un Compte Gratuit',
|
||||||
signed_with: 'Signé avec',
|
powered_by: 'Propulsé par',
|
||||||
please_check_the_box_to_continue: 'Veuillez cocher la case pour continuer',
|
please_check_the_box_to_continue: 'Veuillez cocher la case pour continuer',
|
||||||
open_source_documents_software: 'logiciel de documents open source',
|
open_source_documents_software: 'logiciel de documents open source',
|
||||||
verified_phone_number: 'Vérifier le numéro de téléphone',
|
verified_phone_number: 'Vérifier le numéro de téléphone',
|
||||||
@@ -425,6 +460,10 @@ const fr = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pl = {
|
const pl = {
|
||||||
|
complete: 'Zakończ',
|
||||||
|
sign_and_complete: 'Podpisz i zakończ',
|
||||||
|
invite: 'Zaproś',
|
||||||
|
email: 'E-mail',
|
||||||
approved: 'Zaakceptowany',
|
approved: 'Zaakceptowany',
|
||||||
reviewed: 'Przejrzany',
|
reviewed: 'Przejrzany',
|
||||||
other: 'Inny',
|
other: 'Inny',
|
||||||
@@ -461,7 +500,8 @@ const pl = {
|
|||||||
payment: 'Płatność',
|
payment: 'Płatność',
|
||||||
number_phone_is_invalid: '{number} telefon jest nieprawidłowy',
|
number_phone_is_invalid: '{number} telefon jest nieprawidłowy',
|
||||||
phone: 'Telefon',
|
phone: 'Telefon',
|
||||||
submit_form: 'Wyślij Formularz',
|
start_now: 'Zacznij teraz',
|
||||||
|
continue: 'Kontynuuj',
|
||||||
sign_now: 'Podpisz teraz',
|
sign_now: 'Podpisz teraz',
|
||||||
type_here_: 'Wpisz tutaj...',
|
type_here_: 'Wpisz tutaj...',
|
||||||
optional: 'opcjonalny',
|
optional: 'opcjonalny',
|
||||||
@@ -482,8 +522,10 @@ const pl = {
|
|||||||
type_signature_here: 'Wpisz podpis tutaj',
|
type_signature_here: 'Wpisz podpis tutaj',
|
||||||
type_initial_here: 'Wpisz inicjały tutaj',
|
type_initial_here: 'Wpisz inicjały tutaj',
|
||||||
form_has_been_completed: 'Formularz został wypełniony!',
|
form_has_been_completed: 'Formularz został wypełniony!',
|
||||||
|
document_has_been_signed: 'Dokument został podpisany!',
|
||||||
|
documents_have_been_signed: 'Dokumenty zostały podpisane!',
|
||||||
create_a_free_account: 'Utwórz darmowe konto',
|
create_a_free_account: 'Utwórz darmowe konto',
|
||||||
signed_with: 'Podpisane za pomocą',
|
powered_by: 'Napędzany przez',
|
||||||
please_check_the_box_to_continue: 'Proszę zaznaczyć pole, aby kontynuować',
|
please_check_the_box_to_continue: 'Proszę zaznaczyć pole, aby kontynuować',
|
||||||
open_source_documents_software: 'oprogramowanie do dokumentów open source',
|
open_source_documents_software: 'oprogramowanie do dokumentów open source',
|
||||||
verified_phone_number: 'Zweryfikuj numer telefonu',
|
verified_phone_number: 'Zweryfikuj numer telefonu',
|
||||||
@@ -510,6 +552,10 @@ const pl = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uk = {
|
const uk = {
|
||||||
|
complete: 'Завершити',
|
||||||
|
sign_and_complete: 'Підписати і завершити',
|
||||||
|
invite: 'Запросити',
|
||||||
|
email: 'Електронна пошта',
|
||||||
approved: 'Затверджено',
|
approved: 'Затверджено',
|
||||||
reviewed: 'Переглянуто',
|
reviewed: 'Переглянуто',
|
||||||
other: 'Інше',
|
other: 'Інше',
|
||||||
@@ -546,7 +592,8 @@ const uk = {
|
|||||||
payment: 'Платіж',
|
payment: 'Платіж',
|
||||||
number_phone_is_invalid: '{number} телефон недійсний',
|
number_phone_is_invalid: '{number} телефон недійсний',
|
||||||
phone: 'Телефон',
|
phone: 'Телефон',
|
||||||
submit_form: 'Надіслати Форму',
|
start_now: 'Почати зараз',
|
||||||
|
continue: 'Продовжити',
|
||||||
sign_now: 'Підписати зараз',
|
sign_now: 'Підписати зараз',
|
||||||
type_here_: 'Введіть тут',
|
type_here_: 'Введіть тут',
|
||||||
optional: 'необов’язково',
|
optional: 'необов’язково',
|
||||||
@@ -567,8 +614,10 @@ const uk = {
|
|||||||
type_signature_here: 'Введіть підпис тут',
|
type_signature_here: 'Введіть підпис тут',
|
||||||
type_initial_here: 'Введіть ініціали тут',
|
type_initial_here: 'Введіть ініціали тут',
|
||||||
form_has_been_completed: 'Форму заповнено!',
|
form_has_been_completed: 'Форму заповнено!',
|
||||||
|
document_has_been_signed: 'Документ був підписаний!',
|
||||||
|
documents_have_been_signed: 'Документи були підписані!',
|
||||||
create_a_free_account: 'Створити безкоштовний обліковий запис',
|
create_a_free_account: 'Створити безкоштовний обліковий запис',
|
||||||
signed_with: 'Підписано за допомогою',
|
powered_by: 'Працює на базі',
|
||||||
please_check_the_box_to_continue: 'Будь ласка, позначте прапорець, щоб продовжити',
|
please_check_the_box_to_continue: 'Будь ласка, позначте прапорець, щоб продовжити',
|
||||||
open_source_documents_software: 'відкритий програмний засіб для документів',
|
open_source_documents_software: 'відкритий програмний засіб для документів',
|
||||||
verified_phone_number: 'Підтвердіть номер телефону',
|
verified_phone_number: 'Підтвердіть номер телефону',
|
||||||
@@ -595,6 +644,10 @@ const uk = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cs = {
|
const cs = {
|
||||||
|
complete: 'Dokončit',
|
||||||
|
sign_and_complete: 'Podepsat a dokončit',
|
||||||
|
invite: 'Pozvat',
|
||||||
|
email: 'E-mail',
|
||||||
approved: 'Schváleno',
|
approved: 'Schváleno',
|
||||||
reviewed: 'Zkontrolováno',
|
reviewed: 'Zkontrolováno',
|
||||||
other: 'Jiné',
|
other: 'Jiné',
|
||||||
@@ -631,7 +684,8 @@ const cs = {
|
|||||||
payment: 'Platba',
|
payment: 'Platba',
|
||||||
phone: 'Telefon',
|
phone: 'Telefon',
|
||||||
number_phone_is_invalid: '{number} telefon je neplatný',
|
number_phone_is_invalid: '{number} telefon je neplatný',
|
||||||
submit_form: 'Odeslat formulář',
|
start_now: 'Začít nyní',
|
||||||
|
continue: 'Pokračovat',
|
||||||
sign_now: 'Podepsat nyní',
|
sign_now: 'Podepsat nyní',
|
||||||
type_here_: 'Zadejte zde',
|
type_here_: 'Zadejte zde',
|
||||||
optional: 'volitelné',
|
optional: 'volitelné',
|
||||||
@@ -652,8 +706,10 @@ const cs = {
|
|||||||
type_signature_here: 'Sem zadejte podpis',
|
type_signature_here: 'Sem zadejte podpis',
|
||||||
type_initial_here: 'Sem zadejte iniciály',
|
type_initial_here: 'Sem zadejte iniciály',
|
||||||
form_has_been_completed: 'Formulář byl dokončen!',
|
form_has_been_completed: 'Formulář byl dokončen!',
|
||||||
|
document_has_been_signed: 'Dokument byl podepsán!',
|
||||||
|
documents_have_been_signed: 'Dokumenty byly podepsány!',
|
||||||
create_a_free_account: 'Vytvořit bezplatný účet',
|
create_a_free_account: 'Vytvořit bezplatný účet',
|
||||||
signed_with: 'Podepsáno pomocí',
|
powered_by: 'Poháněno',
|
||||||
please_check_the_box_to_continue: 'Prosím, zaškrtněte políčko pro pokračování',
|
please_check_the_box_to_continue: 'Prosím, zaškrtněte políčko pro pokračování',
|
||||||
open_source_documents_software: 'open source software pro dokumenty',
|
open_source_documents_software: 'open source software pro dokumenty',
|
||||||
verified_phone_number: 'Ověřte telefonní číslo',
|
verified_phone_number: 'Ověřte telefonní číslo',
|
||||||
@@ -680,6 +736,10 @@ const cs = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pt = {
|
const pt = {
|
||||||
|
complete: 'Completar',
|
||||||
|
sign_and_complete: 'Assinar e Completar',
|
||||||
|
invite: 'Convidar',
|
||||||
|
email: 'E-mail',
|
||||||
approved: 'Aprovado',
|
approved: 'Aprovado',
|
||||||
reviewed: 'Revisado',
|
reviewed: 'Revisado',
|
||||||
other: 'Outro',
|
other: 'Outro',
|
||||||
@@ -716,7 +776,8 @@ const pt = {
|
|||||||
payment: 'Pagamento',
|
payment: 'Pagamento',
|
||||||
number_phone_is_invalid: '{number} telefone é inválido',
|
number_phone_is_invalid: '{number} telefone é inválido',
|
||||||
phone: 'Telefone',
|
phone: 'Telefone',
|
||||||
submit_form: 'Enviar Formulário',
|
start_now: 'Começar agora',
|
||||||
|
continue: 'Continuar',
|
||||||
sign_now: 'Assinar agora',
|
sign_now: 'Assinar agora',
|
||||||
type_here_: 'Digite aqui',
|
type_here_: 'Digite aqui',
|
||||||
optional: 'opcional',
|
optional: 'opcional',
|
||||||
@@ -737,8 +798,10 @@ const pt = {
|
|||||||
type_signature_here: 'Digite a assinatura aqui',
|
type_signature_here: 'Digite a assinatura aqui',
|
||||||
type_initial_here: 'Digite as iniciais aqui',
|
type_initial_here: 'Digite as iniciais aqui',
|
||||||
form_has_been_completed: 'O formulário foi concluído!',
|
form_has_been_completed: 'O formulário foi concluído!',
|
||||||
|
document_has_been_signed: 'O documento foi assinado!',
|
||||||
|
documents_have_been_signed: 'Os documentos foram assinados!',
|
||||||
create_a_free_account: 'Criar uma Conta Gratuita',
|
create_a_free_account: 'Criar uma Conta Gratuita',
|
||||||
signed_with: 'Assinado com',
|
powered_by: 'Desenvolvido por',
|
||||||
please_check_the_box_to_continue: 'Por favor, marque a caixa para continuar',
|
please_check_the_box_to_continue: 'Por favor, marque a caixa para continuar',
|
||||||
open_source_documents_software: 'software de documentos de código aberto',
|
open_source_documents_software: 'software de documentos de código aberto',
|
||||||
verified_phone_number: 'Verificar Número de Telefone',
|
verified_phone_number: 'Verificar Número de Telefone',
|
||||||
@@ -765,6 +828,10 @@ const pt = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const he = {
|
const he = {
|
||||||
|
complete: 'השלם',
|
||||||
|
sign_and_complete: 'חתום והשלם',
|
||||||
|
invite: 'הזמן',
|
||||||
|
email: 'דוא"ל',
|
||||||
approved: 'מאושר',
|
approved: 'מאושר',
|
||||||
reviewed: 'נסקר',
|
reviewed: 'נסקר',
|
||||||
other: 'אחר',
|
other: 'אחר',
|
||||||
@@ -801,7 +868,8 @@ const he = {
|
|||||||
payment: 'תשלום',
|
payment: 'תשלום',
|
||||||
phone: 'טלפון',
|
phone: 'טלפון',
|
||||||
number_phone_is_invalid: '{number} טלפון אינו חוקי',
|
number_phone_is_invalid: '{number} טלפון אינו חוקי',
|
||||||
submit_form: 'שלח טופס',
|
start_now: 'התחל עכשיו',
|
||||||
|
continue: 'המשך',
|
||||||
sign_now: 'חתום כעת',
|
sign_now: 'חתום כעת',
|
||||||
type_here_: 'הקלד כאן',
|
type_here_: 'הקלד כאן',
|
||||||
optional: 'אופציונלי',
|
optional: 'אופציונלי',
|
||||||
@@ -823,8 +891,10 @@ const he = {
|
|||||||
type_signature_here: 'הקלד חתימה כאן',
|
type_signature_here: 'הקלד חתימה כאן',
|
||||||
type_initial_here: 'הקלד ציוני ראשי תיבות כאן',
|
type_initial_here: 'הקלד ציוני ראשי תיבות כאן',
|
||||||
form_has_been_completed: 'הטופס הושלם',
|
form_has_been_completed: 'הטופס הושלם',
|
||||||
|
document_has_been_signed: 'המסמך נחתם!',
|
||||||
|
documents_have_been_signed: 'המסמכים נחתמו!',
|
||||||
create_a_free_account: 'צור חשבון חינם',
|
create_a_free_account: 'צור חשבון חינם',
|
||||||
signed_with: 'חתום באמצעות',
|
powered_by: 'מופעל על ידי',
|
||||||
please_check_the_box_to_continue: 'אנא סמן את התיבה כדי להמשיך',
|
please_check_the_box_to_continue: 'אנא סמן את התיבה כדי להמשיך',
|
||||||
open_source_documents_software: 'תוכנה פתוחה למסמכים',
|
open_source_documents_software: 'תוכנה פתוחה למסמכים',
|
||||||
verified_phone_number: 'אימות מספר טלפון',
|
verified_phone_number: 'אימות מספר טלפון',
|
||||||
@@ -851,6 +921,10 @@ const he = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nl = {
|
const nl = {
|
||||||
|
complete: 'Voltooien',
|
||||||
|
sign_and_complete: 'Ondertekenen en voltooien',
|
||||||
|
invite: 'Uitnodigen',
|
||||||
|
email: 'E-mail',
|
||||||
approved: 'Goedgekeurd',
|
approved: 'Goedgekeurd',
|
||||||
reviewed: 'Beoordeeld',
|
reviewed: 'Beoordeeld',
|
||||||
other: 'Anders',
|
other: 'Anders',
|
||||||
@@ -888,7 +962,8 @@ const nl = {
|
|||||||
payment: 'Betaling',
|
payment: 'Betaling',
|
||||||
phone: 'Telefoon',
|
phone: 'Telefoon',
|
||||||
number_phone_is_invalid: '{number} telefoon is ongeldig',
|
number_phone_is_invalid: '{number} telefoon is ongeldig',
|
||||||
submit_form: 'Formulier verzenden',
|
start_now: 'Nu beginnen',
|
||||||
|
continue: 'Doorgaan',
|
||||||
sign_now: 'Nu ondertekenen',
|
sign_now: 'Nu ondertekenen',
|
||||||
type_here_: 'Typ hier...',
|
type_here_: 'Typ hier...',
|
||||||
optional: 'Optioneel',
|
optional: 'Optioneel',
|
||||||
@@ -909,8 +984,10 @@ const nl = {
|
|||||||
type_signature_here: 'Typ hier uw handtekening',
|
type_signature_here: 'Typ hier uw handtekening',
|
||||||
type_initial_here: 'Typ hier uw initialen',
|
type_initial_here: 'Typ hier uw initialen',
|
||||||
form_has_been_completed: 'Formulier is voltooid!',
|
form_has_been_completed: 'Formulier is voltooid!',
|
||||||
|
document_has_been_signed: 'Document is ondertekend!',
|
||||||
|
documents_have_been_signed: 'De documenten zijn ondertekend!',
|
||||||
create_a_free_account: 'Maak een gratis account aan',
|
create_a_free_account: 'Maak een gratis account aan',
|
||||||
signed_with: 'Ondertekend met',
|
powered_by: 'Aangedreven door',
|
||||||
please_check_the_box_to_continue: 'Vink het vakje aan om door te gaan',
|
please_check_the_box_to_continue: 'Vink het vakje aan om door te gaan',
|
||||||
open_source_documents_software: 'Open source documenten software',
|
open_source_documents_software: 'Open source documenten software',
|
||||||
verified_phone_number: 'Geverifieerd telefoonnummer',
|
verified_phone_number: 'Geverifieerd telefoonnummer',
|
||||||
@@ -937,6 +1014,10 @@ const nl = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ar = {
|
const ar = {
|
||||||
|
complete: 'اكتمال',
|
||||||
|
sign_and_complete: 'التوقيع والاكتمال',
|
||||||
|
invite: 'دعوة',
|
||||||
|
email: 'البريد الإلكتروني',
|
||||||
approved: 'موافق عليه',
|
approved: 'موافق عليه',
|
||||||
reviewed: 'تمت مراجعته',
|
reviewed: 'تمت مراجعته',
|
||||||
other: 'آخر',
|
other: 'آخر',
|
||||||
@@ -973,7 +1054,8 @@ const ar = {
|
|||||||
payment: 'الدفع',
|
payment: 'الدفع',
|
||||||
phone: 'هاتف',
|
phone: 'هاتف',
|
||||||
number_phone_is_invalid: '{number} هاتف غير صالح',
|
number_phone_is_invalid: '{number} هاتف غير صالح',
|
||||||
submit_form: 'إرسال النموذج',
|
start_now: 'ابدأ الآن',
|
||||||
|
continue: 'متابعة',
|
||||||
sign_now: 'وقع الآن',
|
sign_now: 'وقع الآن',
|
||||||
type_here_: 'اكتب هنا',
|
type_here_: 'اكتب هنا',
|
||||||
optional: 'اختياري',
|
optional: 'اختياري',
|
||||||
@@ -994,8 +1076,10 @@ const ar = {
|
|||||||
type_signature_here: 'اكتب التوقيع هنا',
|
type_signature_here: 'اكتب التوقيع هنا',
|
||||||
type_initial_here: 'اكتب الاختصارات هنا',
|
type_initial_here: 'اكتب الاختصارات هنا',
|
||||||
form_has_been_completed: 'تم إكمال النموذج!',
|
form_has_been_completed: 'تم إكمال النموذج!',
|
||||||
|
document_has_been_signed: 'تم توقيع الوثيقة!',
|
||||||
|
documents_have_been_signed: 'تم توقيع الوثائق!',
|
||||||
create_a_free_account: 'إنشاء حساب مجاني',
|
create_a_free_account: 'إنشاء حساب مجاني',
|
||||||
signed_with: 'تم التوقيع بواسطة',
|
powered_by: 'مدعوم من',
|
||||||
please_check_the_box_to_continue: 'الرجاء التحقق من الخانة للمتابعة',
|
please_check_the_box_to_continue: 'الرجاء التحقق من الخانة للمتابعة',
|
||||||
open_source_documents_software: 'برنامج وثائق مفتوح المصدر',
|
open_source_documents_software: 'برنامج وثائق مفتوح المصدر',
|
||||||
verified_phone_number: 'تحقق من رقم الهاتف',
|
verified_phone_number: 'تحقق من رقم الهاتف',
|
||||||
@@ -1022,6 +1106,10 @@ const ar = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ko = {
|
const ko = {
|
||||||
|
complete: '완료',
|
||||||
|
sign_and_complete: '서명하고 완료하기',
|
||||||
|
invite: '초대하기',
|
||||||
|
email: '이메일',
|
||||||
approved: '승인됨',
|
approved: '승인됨',
|
||||||
reviewed: '검토됨',
|
reviewed: '검토됨',
|
||||||
other: '기타',
|
other: '기타',
|
||||||
@@ -1057,7 +1145,8 @@ const ko = {
|
|||||||
payment: '결제',
|
payment: '결제',
|
||||||
phone: '전화',
|
phone: '전화',
|
||||||
number_phone_is_invalid: '{number} 전화번호가 유효하지 않습니다',
|
number_phone_is_invalid: '{number} 전화번호가 유효하지 않습니다',
|
||||||
submit_form: '양식 제출',
|
start_now: '지금 시작하기',
|
||||||
|
continue: '계속하다',
|
||||||
sign_now: '지금 서명',
|
sign_now: '지금 서명',
|
||||||
type_here_: '여기에 입력...',
|
type_here_: '여기에 입력...',
|
||||||
optional: '선택 사항',
|
optional: '선택 사항',
|
||||||
@@ -1078,8 +1167,10 @@ const ko = {
|
|||||||
type_signature_here: '여기에 서명 입력',
|
type_signature_here: '여기에 서명 입력',
|
||||||
type_initial_here: '여기에 이니셜 입력',
|
type_initial_here: '여기에 이니셜 입력',
|
||||||
form_has_been_completed: '양식이 완료되었습니다!',
|
form_has_been_completed: '양식이 완료되었습니다!',
|
||||||
|
document_has_been_signed: '문서가 서명되었습니다!',
|
||||||
|
documents_have_been_signed: '문서가 서명되었습니다!',
|
||||||
create_a_free_account: '무료 계정 생성',
|
create_a_free_account: '무료 계정 생성',
|
||||||
signed_with: '다음으로 서명:',
|
powered_by: '구동',
|
||||||
please_check_the_box_to_continue: '계속하려면 확인란을 선택하십시오',
|
please_check_the_box_to_continue: '계속하려면 확인란을 선택하십시오',
|
||||||
open_source_documents_software: '오픈 소스 문서 소프트웨어',
|
open_source_documents_software: '오픈 소스 문서 소프트웨어',
|
||||||
verified_phone_number: '전화번호 확인됨',
|
verified_phone_number: '전화번호 확인됨',
|
||||||
|
|||||||
@@ -50,6 +50,26 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
|
<span
|
||||||
|
class="tooltip"
|
||||||
|
:data-tip="t('click_to_upload')"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="btn btn-outline btn-sm font-medium inline-flex flex-nowrap"
|
||||||
|
>
|
||||||
|
<IconUpload :width="16" />
|
||||||
|
<input
|
||||||
|
:key="uploadImageInputKey"
|
||||||
|
type="file"
|
||||||
|
hidden
|
||||||
|
accept="image/*"
|
||||||
|
@change="drawImage"
|
||||||
|
>
|
||||||
|
<span class="hidden sm:inline">
|
||||||
|
{{ t('upload') }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
<a
|
<a
|
||||||
v-if="modelValue || computedPreviousValue"
|
v-if="modelValue || computedPreviousValue"
|
||||||
href="#"
|
href="#"
|
||||||
@@ -97,7 +117,7 @@
|
|||||||
<img
|
<img
|
||||||
v-if="modelValue || computedPreviousValue"
|
v-if="modelValue || computedPreviousValue"
|
||||||
:src="attachmentsIndex[modelValue || computedPreviousValue].url"
|
:src="attachmentsIndex[modelValue || computedPreviousValue].url"
|
||||||
class="mx-auto bg-white border border-base-300 rounded max-h-72"
|
class="mx-auto bg-white border border-base-300 rounded max-h-44"
|
||||||
>
|
>
|
||||||
<canvas
|
<canvas
|
||||||
v-show="!modelValue && !computedPreviousValue"
|
v-show="!modelValue && !computedPreviousValue"
|
||||||
@@ -120,16 +140,18 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { cropCanvasAndExportToPNG } from './crop_canvas'
|
import { cropCanvasAndExportToPNG } from './crop_canvas'
|
||||||
import { IconReload, IconTextSize, IconSignature, IconArrowsDiagonalMinimize2 } from '@tabler/icons-vue'
|
import { IconReload, IconTextSize, IconUpload, IconSignature, IconArrowsDiagonalMinimize2 } from '@tabler/icons-vue'
|
||||||
import SignaturePad from 'signature_pad'
|
import SignaturePad from 'signature_pad'
|
||||||
import AppearsOn from './appears_on'
|
import AppearsOn from './appears_on'
|
||||||
import MarkdownContent from './markdown_content'
|
import MarkdownContent from './markdown_content'
|
||||||
|
import SignatureStep from './signature_step'
|
||||||
|
|
||||||
const scale = 3
|
const scale = 3
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'InitialsStep',
|
name: 'InitialsStep',
|
||||||
components: {
|
components: {
|
||||||
|
IconUpload,
|
||||||
AppearsOn,
|
AppearsOn,
|
||||||
IconReload,
|
IconReload,
|
||||||
IconTextSize,
|
IconTextSize,
|
||||||
@@ -178,7 +200,8 @@ export default {
|
|||||||
return {
|
return {
|
||||||
isInitialsStarted: !!this.previousValue,
|
isInitialsStarted: !!this.previousValue,
|
||||||
isUsePreviousValue: true,
|
isUsePreviousValue: true,
|
||||||
isDrawInitials: false
|
isDrawInitials: false,
|
||||||
|
uploadImageInputKey: Math.random().toString()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -229,6 +252,15 @@ export default {
|
|||||||
this.intersectionObserver?.disconnect()
|
this.intersectionObserver?.disconnect()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
drawOnCanvas: SignatureStep.methods.drawOnCanvas,
|
||||||
|
drawImage (event) {
|
||||||
|
this.remove()
|
||||||
|
this.isInitialsStarted = true
|
||||||
|
|
||||||
|
this.drawOnCanvas(event.target.files[0], this.$refs.canvas)
|
||||||
|
|
||||||
|
this.uploadImageInputKey = Math.random().toString()
|
||||||
|
},
|
||||||
remove () {
|
remove () {
|
||||||
this.$emit('update:model-value', '')
|
this.$emit('update:model-value', '')
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<template>
|
||||||
|
<form
|
||||||
|
ref="form"
|
||||||
|
action="post"
|
||||||
|
method="post"
|
||||||
|
class="mx-auto"
|
||||||
|
@submit.prevent="submit"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="authenticity_token"
|
||||||
|
:value="authenticityToken"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(submitter, index) in submitters"
|
||||||
|
:key="submitter.uuid"
|
||||||
|
:class="{ 'mt-4': index !== 0 }"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
:value="submitter.uuid"
|
||||||
|
hidden
|
||||||
|
name="submission[submitters][][uuid]"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="submitter.uuid"
|
||||||
|
dir="auto"
|
||||||
|
class="label text-2xl"
|
||||||
|
>
|
||||||
|
{{ t('invite') }} {{ submitter.name }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
:id="submitter.uuid"
|
||||||
|
dir="auto"
|
||||||
|
class="base-input !text-2xl w-full"
|
||||||
|
:placeholder="t('email')"
|
||||||
|
type="email"
|
||||||
|
required
|
||||||
|
autofocus="true"
|
||||||
|
name="submission[submitters][][email]"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mt-6 md:mt-8"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="base-button w-full flex justify-center"
|
||||||
|
:disabled="isSubmitting"
|
||||||
|
>
|
||||||
|
<span class="flex">
|
||||||
|
<IconInnerShadowTop
|
||||||
|
v-if="isSubmitting"
|
||||||
|
class="mr-1 animate-spin"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{{ t('submit') }}
|
||||||
|
</span><span
|
||||||
|
v-if="isSubmitting"
|
||||||
|
class="w-6 flex justify-start mr-1"
|
||||||
|
><span>...</span></span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { IconInnerShadowTop } from '@tabler/icons-vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'InviteForm',
|
||||||
|
components: {
|
||||||
|
IconInnerShadowTop
|
||||||
|
},
|
||||||
|
inject: ['t'],
|
||||||
|
props: {
|
||||||
|
submitters: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
authenticityToken: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
submitterSlug: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['success'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isSubmitting: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit () {
|
||||||
|
this.isSubmitting = true
|
||||||
|
|
||||||
|
return fetch(this.url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: new FormData(this.$refs.form)
|
||||||
|
}).then((response) => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
this.$emit('success')
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.isSubmitting = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -569,8 +569,11 @@ export default {
|
|||||||
this.remove()
|
this.remove()
|
||||||
this.isSignatureStarted = true
|
this.isSignatureStarted = true
|
||||||
|
|
||||||
const file = event.target.files[0]
|
this.drawOnCanvas(event.target.files[0], this.$refs.canvas)
|
||||||
|
|
||||||
|
this.uploadImageInputKey = Math.random().toString()
|
||||||
|
},
|
||||||
|
drawOnCanvas (file, canvas) {
|
||||||
if (file && file.type.match('image.*')) {
|
if (file && file.type.match('image.*')) {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
|
|
||||||
@@ -580,7 +583,6 @@ export default {
|
|||||||
img.src = event.target.result
|
img.src = event.target.result
|
||||||
|
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
const canvas = this.$refs.canvas
|
|
||||||
const context = canvas.getContext('2d')
|
const context = canvas.getContext('2d')
|
||||||
|
|
||||||
const aspectRatio = img.width / img.height
|
const aspectRatio = img.width / img.height
|
||||||
@@ -615,8 +617,6 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reader.readAsDataURL(file)
|
reader.readAsDataURL(file)
|
||||||
|
|
||||||
this.uploadImageInputKey = Math.random().toString()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
maybeSetSignedUuid (signedUuid) {
|
maybeSetSignedUuid (signedUuid) {
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export default {
|
|||||||
const textarea = this.$refs.textarea
|
const textarea = this.$refs.textarea
|
||||||
|
|
||||||
textarea.style.height = 'auto'
|
textarea.style.height = 'auto'
|
||||||
textarea.style.height = textarea.scrollHeight + 'px'
|
textarea.style.height = Math.min(250, textarea.scrollHeight) + 'px'
|
||||||
},
|
},
|
||||||
toggleTextArea () {
|
toggleTextArea () {
|
||||||
this.isTextArea = true
|
this.isTextArea = true
|
||||||
|
|||||||
@@ -360,6 +360,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
fieldNames: FieldType.computed.fieldNames,
|
fieldNames: FieldType.computed.fieldNames,
|
||||||
|
fieldLabels: FieldType.computed.fieldLabels,
|
||||||
fieldIcons: FieldType.computed.fieldIcons,
|
fieldIcons: FieldType.computed.fieldIcons,
|
||||||
isDefaultValuePresent () {
|
isDefaultValuePresent () {
|
||||||
if (this.field?.type === 'radio' && this.field?.areas?.length > 1) {
|
if (this.field?.type === 'radio' && this.field?.areas?.length > 1) {
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
/>
|
/>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a
|
<a
|
||||||
|
v-if="withSignYourselfButton"
|
||||||
:href="template.submitters.length > 1 ? `/templates/${template.id}/submissions/new?selfsign=true` : `/d/${template.slug}`"
|
:href="template.submitters.length > 1 ? `/templates/${template.id}/submissions/new?selfsign=true` : `/d/${template.slug}`"
|
||||||
class="btn btn-primary btn-ghost text-base hidden md:flex"
|
class="btn btn-primary btn-ghost text-base hidden md:flex"
|
||||||
:target="template.submitters.length > 1 ? '' : '_blank'"
|
:target="template.submitters.length > 1 ? '' : '_blank'"
|
||||||
@@ -73,6 +74,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
|
v-if="withSendButton"
|
||||||
:href="`/templates/${template.id}/submissions/new?with_link=true`"
|
:href="`/templates/${template.id}/submissions/new?with_link=true`"
|
||||||
data-turbo-frame="modal"
|
data-turbo-frame="modal"
|
||||||
class="white-button md:!px-6"
|
class="white-button md:!px-6"
|
||||||
@@ -129,7 +131,18 @@
|
|||||||
class="flex items-center justify-center space-x-2"
|
class="flex items-center justify-center space-x-2"
|
||||||
>
|
>
|
||||||
<IconEye class="w-6 h-6 flex-shrink-0" />
|
<IconEye class="w-6 h-6 flex-shrink-0" />
|
||||||
<span class="whitespace-nowrap">Save and Preview</span>
|
<span class="whitespace-nowrap">{{ t('save_and_preview') }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
:href="`/templates/${template.id}/preferences`"
|
||||||
|
data-turbo-frame="modal"
|
||||||
|
class="flex space-x-2"
|
||||||
|
@click="closeDropdown"
|
||||||
|
>
|
||||||
|
<IconAdjustments class="w-6 h-6 flex-shrink-0" />
|
||||||
|
<span class="whitespace-nowrap">{{ t('preferences') }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -319,7 +332,7 @@
|
|||||||
>
|
>
|
||||||
<div class="bg-base-200 rounded-lg p-5 text-center space-y-4">
|
<div class="bg-base-200 rounded-lg p-5 text-center space-y-4">
|
||||||
<p>
|
<p>
|
||||||
{{ t('draw_field_on_the_document').replace('{field}', drawField?.name || '') }}
|
{{ t('draw_field_on_the_document') }}
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
@@ -402,10 +415,10 @@ import Contenteditable from './contenteditable'
|
|||||||
import DocumentPreview from './preview'
|
import DocumentPreview from './preview'
|
||||||
import DocumentControls from './controls'
|
import DocumentControls from './controls'
|
||||||
import MobileFields from './mobile_fields'
|
import MobileFields from './mobile_fields'
|
||||||
import { IconPlus, IconUsersPlus, IconDeviceFloppy, IconChevronDown, IconEye, IconWritingSign, IconInnerShadowTop, IconInfoCircle } from '@tabler/icons-vue'
|
import { IconPlus, IconUsersPlus, IconDeviceFloppy, IconChevronDown, IconEye, IconWritingSign, IconInnerShadowTop, IconInfoCircle, IconAdjustments } from '@tabler/icons-vue'
|
||||||
import { v4 } from 'uuid'
|
import { v4 } from 'uuid'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { en as i18nEn } from './i18n'
|
import * as i18n from './i18n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TemplateBuilder',
|
name: 'TemplateBuilder',
|
||||||
@@ -426,6 +439,7 @@ export default {
|
|||||||
Contenteditable,
|
Contenteditable,
|
||||||
IconUsersPlus,
|
IconUsersPlus,
|
||||||
IconChevronDown,
|
IconChevronDown,
|
||||||
|
IconAdjustments,
|
||||||
IconEye,
|
IconEye,
|
||||||
IconDeviceFloppy
|
IconDeviceFloppy
|
||||||
},
|
},
|
||||||
@@ -479,6 +493,16 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
withSendButton: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
withSignYourselfButton: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
inputMode: {
|
inputMode: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -655,6 +679,9 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
selectedAreaRef: () => ref(),
|
selectedAreaRef: () => ref(),
|
||||||
fieldsDragFieldRef: () => ref(),
|
fieldsDragFieldRef: () => ref(),
|
||||||
|
language () {
|
||||||
|
return this.locale.split('-')[0].toLowerCase()
|
||||||
|
},
|
||||||
defaultDateFormat () {
|
defaultDateFormat () {
|
||||||
const isUsBrowser = Intl.DateTimeFormat().resolvedOptions().locale.endsWith('-US')
|
const isUsBrowser = Intl.DateTimeFormat().resolvedOptions().locale.endsWith('-US')
|
||||||
const isUsTimezone = new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' }).format(new Date()).match(/\s(?:CST|CDT|PST|PDT|EST|EDT)$/)
|
const isUsTimezone = new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' }).format(new Date()).match(/\s(?:CST|CDT|PST|PDT|EST|EDT)$/)
|
||||||
@@ -758,8 +785,11 @@ export default {
|
|||||||
this.documentRefs = []
|
this.documentRefs = []
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
closeDropdown () {
|
||||||
|
document.activeElement.blur()
|
||||||
|
},
|
||||||
t (key) {
|
t (key) {
|
||||||
return this.i18n[key] || i18nEn[key] || key
|
return this.i18n[key] || i18n[this.language]?.[key] || i18n.en[key] || key
|
||||||
},
|
},
|
||||||
removePendingFields () {
|
removePendingFields () {
|
||||||
this.template.fields = this.template.fields.filter((f) => {
|
this.template.fields = this.template.fields.filter((f) => {
|
||||||
@@ -1325,7 +1355,7 @@ export default {
|
|||||||
this.save()
|
this.save()
|
||||||
},
|
},
|
||||||
onDocumentRemove (item) {
|
onDocumentRemove (item) {
|
||||||
if (window.confirm(this.t('are_you_sure'))) {
|
if (window.confirm(this.t('are_you_sure_'))) {
|
||||||
this.template.schema.splice(this.template.schema.indexOf(item), 1)
|
this.template.schema.splice(this.template.schema.indexOf(item), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1424,7 +1454,7 @@ export default {
|
|||||||
if (!this.template.fields.length) {
|
if (!this.template.fields.length) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
alert('Please draw fields to prepare the document.')
|
alert(this.t('please_draw_fields_to_prepare_the_document'))
|
||||||
} else {
|
} else {
|
||||||
const submitterWithoutFields =
|
const submitterWithoutFields =
|
||||||
this.template.submitters.find((submitter) => !this.template.fields.some((f) => f.submitter_uuid === submitter.uuid))
|
this.template.submitters.find((submitter) => !this.template.fields.some((f) => f.submitter_uuid === submitter.uuid))
|
||||||
@@ -1432,7 +1462,7 @@ export default {
|
|||||||
if (submitterWithoutFields) {
|
if (submitterWithoutFields) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
alert(`Please add fields for the ${submitterWithoutFields.name}. Or, remove the ${submitterWithoutFields.name} if not needed.`)
|
alert(this.t('please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed').replaceAll('{submitter_name}', submitterWithoutFields.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1448,13 +1478,13 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.template.fields.length) {
|
if (!this.template.fields.length) {
|
||||||
alert('Please draw fields to prepare the document.')
|
alert(this.t('please_draw_fields_to_prepare_the_document'))
|
||||||
} else {
|
} else {
|
||||||
const submitterWithoutFields =
|
const submitterWithoutFields =
|
||||||
this.template.submitters.find((submitter) => !this.template.fields.some((f) => f.submitter_uuid === submitter.uuid))
|
this.template.submitters.find((submitter) => !this.template.fields.some((f) => f.submitter_uuid === submitter.uuid))
|
||||||
|
|
||||||
if (submitterWithoutFields) {
|
if (submitterWithoutFields) {
|
||||||
alert(`Please add fields for the ${submitterWithoutFields.name}. Or, remove the ${submitterWithoutFields.name} if not needed.`)
|
alert(this.t('please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed').replaceAll('{submitter_name}', submitterWithoutFields.name))
|
||||||
} else {
|
} else {
|
||||||
this.isSaving = true
|
this.isSaving = true
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
href="https://www.docuseal.co/pricing"
|
href="https://www.docuseal.co/pricing"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="link"
|
class="link"
|
||||||
>Available in Pro</a>
|
>{{ t('available_in_pro') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<form @submit.prevent="validateSaveAndClose">
|
<form @submit.prevent="validateSaveAndClose">
|
||||||
<div class="my-4 space-y-5">
|
<div class="my-4 space-y-5">
|
||||||
@@ -200,7 +200,7 @@ export default {
|
|||||||
},
|
},
|
||||||
validateSaveAndClose () {
|
validateSaveAndClose () {
|
||||||
if (!this.withConditions) {
|
if (!this.withConditions) {
|
||||||
return alert('Available only in Pro')
|
return alert(this.t('available_only_in_pro'))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.conditions.find((f) => f.field_uuid)) {
|
if (this.conditions.find((f) => f.field_uuid)) {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export default {
|
|||||||
|
|
||||||
this.upload()
|
this.upload()
|
||||||
} else {
|
} else {
|
||||||
alert('Only PDF and images are supported.')
|
alert(this.t('only_pdf_and_images_are_supported'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,6 +312,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
fieldNames: FieldType.computed.fieldNames,
|
fieldNames: FieldType.computed.fieldNames,
|
||||||
|
fieldLabels: FieldType.computed.fieldLabels,
|
||||||
dropdownBgColor () {
|
dropdownBgColor () {
|
||||||
return ['', null, 'transparent'].includes(this.backgroundColor) ? 'white' : this.backgroundColor
|
return ['', null, 'transparent'].includes(this.backgroundColor) ? 'white' : this.backgroundColor
|
||||||
},
|
},
|
||||||
@@ -367,8 +368,7 @@ export default {
|
|||||||
if (this.field.type === 'heading') {
|
if (this.field.type === 'heading') {
|
||||||
return `${this.fieldNames[field.type]} ${typeIndex + 1}`
|
return `${this.fieldNames[field.type]} ${typeIndex + 1}`
|
||||||
} else {
|
} else {
|
||||||
const suffix = { multiple: this.t('select'), radio: this.t('group') }[field.type] || this.t('field')
|
return `${this.fieldLabels[field.type]} ${typeIndex + 1}`
|
||||||
return `${this.fieldNames[field.type]} ${suffix} ${typeIndex + 1}`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ export default {
|
|||||||
this.$emit('update:model-value', submitter.uuid)
|
this.$emit('update:model-value', submitter.uuid)
|
||||||
},
|
},
|
||||||
remove (submitter) {
|
remove (submitter) {
|
||||||
if (window.confirm(this.t('are_you_sure'))) {
|
if (window.confirm(this.t('are_you_sure_'))) {
|
||||||
this.$emit('remove', submitter)
|
this.$emit('remove', submitter)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -114,6 +114,25 @@ export default {
|
|||||||
phone: this.t('phone')
|
phone: this.t('phone')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
fieldLabels () {
|
||||||
|
return {
|
||||||
|
text: this.t('text_field'),
|
||||||
|
signature: this.t('signature_field'),
|
||||||
|
initials: this.t('initials_field'),
|
||||||
|
date: this.t('date_field'),
|
||||||
|
number: this.t('number_field'),
|
||||||
|
image: this.t('image_field'),
|
||||||
|
file: this.t('file_field'),
|
||||||
|
select: this.t('select_field'),
|
||||||
|
checkbox: this.t('checkbox_field'),
|
||||||
|
multiple: this.t('multiple_field'),
|
||||||
|
radio: this.t('radio_field'),
|
||||||
|
cells: this.t('cells_field'),
|
||||||
|
stamp: this.t('stamp_field'),
|
||||||
|
payment: this.t('payment_field'),
|
||||||
|
phone: this.t('phone_field')
|
||||||
|
}
|
||||||
|
},
|
||||||
fieldIcons () {
|
fieldIcons () {
|
||||||
return {
|
return {
|
||||||
heading: IconHeading,
|
heading: IconHeading,
|
||||||
|
|||||||
@@ -137,7 +137,7 @@
|
|||||||
v-else-if="type == 'phone' && (fieldTypes.length === 0 || fieldTypes.includes(type))"
|
v-else-if="type == 'phone' && (fieldTypes.length === 0 || fieldTypes.includes(type))"
|
||||||
class="tooltip tooltip-bottom flex"
|
class="tooltip tooltip-bottom flex"
|
||||||
:class="{'tooltip-bottom-end': withPayment, 'tooltip-bottom': !withPayment }"
|
:class="{'tooltip-bottom-end': withPayment, 'tooltip-bottom': !withPayment }"
|
||||||
data-tip="Unlock SMS-verified phone number field with paid plan. Use text field for phone numbers without verification."
|
:data-tip="t('unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification')"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="https://www.docuseal.co/pricing"
|
href="https://www.docuseal.co/pricing"
|
||||||
@@ -168,13 +168,13 @@
|
|||||||
>
|
>
|
||||||
<ul class="list-disc list-outside ml-3">
|
<ul class="list-disc list-outside ml-3">
|
||||||
<li>
|
<li>
|
||||||
Draw a text field on the page with a mouse
|
{{ t('draw_a_text_field_on_the_page_with_a_mouse') }}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Drag & drop any other field type on the page
|
{{ t('drag_and_drop_any_other_field_type_on_the_page') }}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Click on the field type above to start drawing it
|
{{ t('click_on_the_field_type_above_to_start_drawing_it') }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
href="https://www.docuseal.co/pricing"
|
href="https://www.docuseal.co/pricing"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="link"
|
class="link"
|
||||||
>Available in Pro</a>
|
>{{ t('available_in_pro') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-inline mb-2 gap-2 space-y-1">
|
<div class="flex-inline mb-2 gap-2 space-y-1">
|
||||||
<button
|
<button
|
||||||
@@ -195,13 +195,13 @@ export default {
|
|||||||
},
|
},
|
||||||
validateSaveAndClose () {
|
validateSaveAndClose () {
|
||||||
if (!this.withFormula) {
|
if (!this.withFormula) {
|
||||||
return alert('Available only in Pro')
|
return alert(this.t('available_only_in_pro'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedFormula = this.normalizeFormula(this.formula)
|
const normalizedFormula = this.normalizeFormula(this.formula)
|
||||||
|
|
||||||
if (normalizedFormula.includes('FIELD NOT FOUND')) {
|
if (normalizedFormula.includes('FIELD NOT FOUND')) {
|
||||||
alert('Some fields are missing in the formula.')
|
alert(this.t('some_fields_are_missing_in_the_formula'))
|
||||||
} else {
|
} else {
|
||||||
this.field.preferences.formula = normalizedFormula
|
this.field.preferences.formula = normalizedFormula
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const en = {
|
|||||||
select_value_: 'Select value...',
|
select_value_: 'Select value...',
|
||||||
remove_condition: 'Remove condition',
|
remove_condition: 'Remove condition',
|
||||||
add_condition: 'Add condition',
|
add_condition: 'Add condition',
|
||||||
are_you_sure: 'Are you sure?',
|
are_you_sure_: 'Are you sure?',
|
||||||
sign_yourself: 'Sign Yourself',
|
sign_yourself: 'Sign Yourself',
|
||||||
set_signing_date: 'Set signing date',
|
set_signing_date: 'Set signing date',
|
||||||
signing_date: 'Signing Date',
|
signing_date: 'Signing Date',
|
||||||
@@ -46,7 +46,7 @@ const en = {
|
|||||||
drawn: 'Drawn',
|
drawn: 'Drawn',
|
||||||
formula: 'Formula',
|
formula: 'Formula',
|
||||||
typed: 'Typed',
|
typed: 'Typed',
|
||||||
draw_field_on_the_document: 'Draw {field} field on the document',
|
draw_field_on_the_document: 'Draw a field on the document',
|
||||||
click_to_upload: 'Click to upload',
|
click_to_upload: 'Click to upload',
|
||||||
or_drag_and_drop_files: 'or drag and drop files',
|
or_drag_and_drop_files: 'or drag and drop files',
|
||||||
uploading: 'Uploading',
|
uploading: 'Uploading',
|
||||||
@@ -101,9 +101,31 @@ const en = {
|
|||||||
stamp: 'Stamp',
|
stamp: 'Stamp',
|
||||||
payment: 'Payment',
|
payment: 'Payment',
|
||||||
phone: 'Phone',
|
phone: 'Phone',
|
||||||
field: 'Field',
|
text_field: 'Text Field',
|
||||||
group: 'Group',
|
signature_field: 'Signature Field',
|
||||||
|
initials_field: 'Initials Field',
|
||||||
|
date_field: 'Date Field',
|
||||||
|
number_field: 'Number Field',
|
||||||
|
image_field: 'Image Field',
|
||||||
|
file_field: 'File Field',
|
||||||
|
select_field: 'Select Field',
|
||||||
|
checkbox_field: 'Checkbox Field',
|
||||||
|
multiple_field: 'Multiple Select Field',
|
||||||
|
radio_field: 'Radio Group Field',
|
||||||
|
cells_field: 'Cells Field',
|
||||||
|
stamp_field: 'Stamp Field',
|
||||||
|
payment_field: 'Payment Field',
|
||||||
|
phone_field: 'Phone Field',
|
||||||
draw_a_text_field_on_the_page_with_a_mouse: 'Draw a text field on the page with a mouse',
|
draw_a_text_field_on_the_page_with_a_mouse: 'Draw a text field on the page with a mouse',
|
||||||
|
drag_and_drop_any_other_field_type_on_the_page: 'Drag & drop any other field type on the page',
|
||||||
|
click_on_the_field_type_above_to_start_drawing_it: 'Click on the field type above to start drawing it',
|
||||||
|
please_draw_fields_to_prepare_the_document: 'Please draw fields to prepare the document.',
|
||||||
|
only_pdf_and_images_are_supported: 'Only PDF and images are supported.',
|
||||||
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Unlock SMS-verified phone number field with paid plan. Use text field for phone numbers without verification.',
|
||||||
|
available_only_in_pro: 'Available only in Pro',
|
||||||
|
failed_to_download_files: 'Failed to download files',
|
||||||
|
signature_is_too_small_please_redraw: 'Signature is too small - please redraw.',
|
||||||
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Please add fields for the {submitter_name}. Or, remove the {submitter_name} if not needed.',
|
||||||
draw_field: 'Draw {field} Field',
|
draw_field: 'Draw {field} Field',
|
||||||
replace: 'Replace',
|
replace: 'Replace',
|
||||||
uploading_: 'Uploading...',
|
uploading_: 'Uploading...',
|
||||||
@@ -117,7 +139,775 @@ const en = {
|
|||||||
custom: 'Custom',
|
custom: 'Custom',
|
||||||
numbers_only: 'Numbers only',
|
numbers_only: 'Numbers only',
|
||||||
letters_only: 'Letters only',
|
letters_only: 'Letters only',
|
||||||
regexp_validation: 'Regexp validation'
|
regexp_validation: 'Regexp validation',
|
||||||
|
enter_pdf_password: 'Enter PDF password',
|
||||||
|
wrong_password: 'Wrong password',
|
||||||
|
currency: 'Currency',
|
||||||
|
save_and_preview: 'Save and Preview',
|
||||||
|
preferences: 'Preferences',
|
||||||
|
available_in_pro: 'Available in Pro',
|
||||||
|
some_fields_are_missing_in_the_formula: 'Some fields are missing in the formula.',
|
||||||
|
learn_more: 'Learn more'
|
||||||
}
|
}
|
||||||
|
|
||||||
export { en }
|
const es = {
|
||||||
|
editable: 'Editable',
|
||||||
|
search_field: 'Campo de búsqueda',
|
||||||
|
field_not_found: 'Campo no encontrado',
|
||||||
|
clear: 'Borrar',
|
||||||
|
type_value: 'Escriba valor',
|
||||||
|
align: 'Alinear',
|
||||||
|
add_all_required_fields_to_continue: 'Agregar todos los campos requeridos para continuar',
|
||||||
|
uploaded_pdf_contains_form_fields_keep_or_remove_them: 'El PDF cargado tiene campos. ¿Mantenerlos o eliminarlos?',
|
||||||
|
keep: 'Mantener',
|
||||||
|
left: 'Izquierda',
|
||||||
|
heading: 'Encabezado',
|
||||||
|
validation: 'Validación',
|
||||||
|
add_blank_page: 'Agregar página en blanco',
|
||||||
|
right: 'Derecha',
|
||||||
|
center: 'Centro',
|
||||||
|
with_logo: 'Con logotipo',
|
||||||
|
description: 'Descripción',
|
||||||
|
signing_date: 'Fecha de Firma',
|
||||||
|
display_title: 'Título de visualización',
|
||||||
|
unchecked: 'No marcado',
|
||||||
|
price: 'Precio',
|
||||||
|
equal: 'Igual',
|
||||||
|
not_equal: 'No es igual',
|
||||||
|
contains: 'Contiene',
|
||||||
|
does_not_contain: 'No contiene',
|
||||||
|
not_empty: 'No vacío',
|
||||||
|
empty: 'Vacío',
|
||||||
|
select_field_: 'Seleccionar campo...',
|
||||||
|
select_value_: 'Seleccionar valor...',
|
||||||
|
remove_condition: 'Eliminar condición',
|
||||||
|
add_condition: 'Agregar condición',
|
||||||
|
condition: 'Condición',
|
||||||
|
formula: 'Fórmula',
|
||||||
|
edit: 'Editar',
|
||||||
|
settings: 'Configuración',
|
||||||
|
up: 'Arriba',
|
||||||
|
down: 'Abajo',
|
||||||
|
set_signing_date: 'Establecer fecha de firma',
|
||||||
|
are_you_sure_: '¿Estás seguro?',
|
||||||
|
sign_yourself: 'Firma tú mismo',
|
||||||
|
checked: 'Seleccionado',
|
||||||
|
send: 'Enviar',
|
||||||
|
remove: 'Eliminar',
|
||||||
|
save: 'Guardar',
|
||||||
|
cancel: 'Cancelar',
|
||||||
|
or_add_field_without_drawing: 'O añadir campo sin dibujar',
|
||||||
|
draw_field_on_the_document: 'Dibujar un campo en el documento',
|
||||||
|
click_to_upload: 'Haz clic para cargar',
|
||||||
|
or_drag_and_drop_files: 'o arrastra y suelta archivos',
|
||||||
|
uploading: 'Subiendo',
|
||||||
|
processing_: 'Procesando...',
|
||||||
|
add_pdf_documents_or_images: 'Agregar documentos PDF o imágenes',
|
||||||
|
add_documents_or_images: 'Agregar documentos o imágenes',
|
||||||
|
required: 'Requerido',
|
||||||
|
default_value: 'Valor predeterminado',
|
||||||
|
format: 'Formato',
|
||||||
|
read_only: 'Solo lectura',
|
||||||
|
page: 'Página',
|
||||||
|
draw_new_area: 'Dibujar nueva área',
|
||||||
|
copy_to_all_pages: 'Copiar a todas las páginas',
|
||||||
|
add_option: 'Agregar opción',
|
||||||
|
option: 'Opción',
|
||||||
|
first_party: 'Primera Parte',
|
||||||
|
second_party: 'Segunda Parte',
|
||||||
|
third_party: 'Tercera Parte',
|
||||||
|
fourth_party: 'Cuarta Parte',
|
||||||
|
fifth_party: 'Quinta Parte',
|
||||||
|
sixth_party: 'Sexta Parte',
|
||||||
|
seventh_party: 'Séptima Parte',
|
||||||
|
eighth_party: 'Octava Parte',
|
||||||
|
ninth_party: 'Novena Parte',
|
||||||
|
tenth_party: 'Décima Parte',
|
||||||
|
eleventh_party: 'Undécimo Partido',
|
||||||
|
twelfth_party: 'Duodécimo Partido',
|
||||||
|
thirteenth_party: 'Decimotercer Partido',
|
||||||
|
fourteenth_party: 'Catorceavo Partido',
|
||||||
|
fifteenth_party: 'Quinceavo Partido',
|
||||||
|
sixteenth_party: 'Dieciséisavo Partido',
|
||||||
|
seventeenth_party: 'Diecisieteavo Partido',
|
||||||
|
eighteenth_party: 'Dieciochoavo Partido',
|
||||||
|
nineteenth_party: 'Decimonovena Fiesta',
|
||||||
|
twentieth_party: 'Vigésima Fiesta',
|
||||||
|
draw: 'Dibujar',
|
||||||
|
add: 'Agregar',
|
||||||
|
text: 'Texto',
|
||||||
|
signature: 'Firma',
|
||||||
|
initials: 'Iniciales',
|
||||||
|
date: 'Fecha',
|
||||||
|
number: 'Número',
|
||||||
|
image: 'Imagen',
|
||||||
|
file: 'Archivo',
|
||||||
|
select: 'Seleccionar',
|
||||||
|
checkbox: 'Casilla',
|
||||||
|
multiple: 'Múltiple',
|
||||||
|
radio: 'Radio',
|
||||||
|
cells: 'Celdas',
|
||||||
|
stamp: 'Sello',
|
||||||
|
payment: 'Pago',
|
||||||
|
phone: 'Teléfono',
|
||||||
|
text_field: 'Campo de Texto',
|
||||||
|
signature_field: 'Campo de Firma',
|
||||||
|
initials_field: 'Campo de Iniciales',
|
||||||
|
date_field: 'Campo de Fecha',
|
||||||
|
number_field: 'Campo de Número',
|
||||||
|
image_field: 'Campo de Imagen',
|
||||||
|
file_field: 'Campo de Archivo',
|
||||||
|
select_field: 'Campo de Selección',
|
||||||
|
checkbox_field: 'Campo de Casilla',
|
||||||
|
multiple_field: 'Campo Múltiple',
|
||||||
|
radio_field: 'Campo de Grupo Radio',
|
||||||
|
cells_field: 'Campo de Celdas',
|
||||||
|
stamp_field: 'Campo de Sello',
|
||||||
|
payment_field: 'Campo de Pago',
|
||||||
|
phone_field: 'Campo de Teléfono',
|
||||||
|
draw_a_text_field_on_the_page_with_a_mouse: 'Dibujar un campo de texto en la página con el mouse',
|
||||||
|
drag_and_drop_any_other_field_type_on_the_page: 'Arrastra y suelta cualquier otro tipo de campo en la página',
|
||||||
|
click_on_the_field_type_above_to_start_drawing_it: 'Haz clic en el tipo de campo de arriba para comenzar a dibujarlo',
|
||||||
|
please_draw_fields_to_prepare_the_document: 'Por favor, dibuja los campos para preparar el documento.',
|
||||||
|
only_pdf_and_images_are_supported: 'Solo se admiten PDF e imágenes.',
|
||||||
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Desbloquea el campo de número de teléfono verificado por SMS con un plan pago. Usa el campo de texto para números de teléfono sin verificación.',
|
||||||
|
available_only_in_pro: 'Disponible solo en Pro',
|
||||||
|
failed_to_download_files: 'Error al descargar los archivos',
|
||||||
|
signature_is_too_small_please_redraw: 'La firma es demasiado pequeña. Por favor, dibújala de nuevo.',
|
||||||
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Por favor, añade campos para {submitter_name} o elimina {submitter_name} si no es necesario.',
|
||||||
|
draw_field: 'Dibujar campo {field}',
|
||||||
|
replace: 'Reemplazar',
|
||||||
|
uploading_: 'Subiendo...',
|
||||||
|
add_document: 'Subir',
|
||||||
|
any: 'Cualquier',
|
||||||
|
drawn: 'Dibujado',
|
||||||
|
typed: 'Escrito',
|
||||||
|
none: 'Ninguno',
|
||||||
|
ssn: 'SSN',
|
||||||
|
ein: 'EIN',
|
||||||
|
email: 'Correo electrónico',
|
||||||
|
url: 'URL',
|
||||||
|
zip: 'ZIP',
|
||||||
|
custom: 'Personalizado',
|
||||||
|
numbers_only: 'Solo números',
|
||||||
|
letters_only: 'Solo letras',
|
||||||
|
regexp_validation: 'Validación de expresión regular',
|
||||||
|
enter_pdf_password: 'Ingrese la contraseña del PDF',
|
||||||
|
wrong_password: 'Contraseña incorrecta',
|
||||||
|
currency: 'Moneda',
|
||||||
|
save_and_preview: 'Guardar y previsualizar',
|
||||||
|
preferences: 'Preferencias',
|
||||||
|
available_in_pro: 'Disponible en Pro',
|
||||||
|
some_fields_are_missing_in_the_formula: 'Faltan algunos campos en la fórmula.',
|
||||||
|
learn_more: 'Aprende más'
|
||||||
|
}
|
||||||
|
|
||||||
|
const it = {
|
||||||
|
editable: 'Modificabile',
|
||||||
|
search_field: 'Campo di ricerca',
|
||||||
|
field_not_found: 'Campo non trovato',
|
||||||
|
clear: 'Cancella',
|
||||||
|
align: 'Allinea',
|
||||||
|
add_all_required_fields_to_continue: 'Aggiungi tutti i campi obbligatori per continuare',
|
||||||
|
uploaded_pdf_contains_form_fields_keep_or_remove_them: 'Il PDF caricato contiene campi del modulo. Mantenerli o rimuoverli?',
|
||||||
|
keep: 'Mantieni',
|
||||||
|
left: 'Sinistra',
|
||||||
|
heading: 'Intestazione',
|
||||||
|
validation: 'Validazione',
|
||||||
|
add_blank_page: 'Aggiungi pagina vuota',
|
||||||
|
right: 'Destra',
|
||||||
|
center: 'Centro',
|
||||||
|
description: 'Descrizione',
|
||||||
|
display_title: 'Mostra titolo',
|
||||||
|
with_logo: 'Con logo',
|
||||||
|
unchecked: 'Non selezionato',
|
||||||
|
price: 'Prezzo',
|
||||||
|
type_value: 'Inserisci valore',
|
||||||
|
equal: 'Uguale',
|
||||||
|
not_equal: 'Non uguale',
|
||||||
|
contains: 'Contiene',
|
||||||
|
does_not_contain: 'Non contiene',
|
||||||
|
not_empty: 'Non vuoto',
|
||||||
|
empty: 'Vuoto',
|
||||||
|
select_field_: 'Seleziona campo...',
|
||||||
|
select_value_: 'Seleziona valore...',
|
||||||
|
remove_condition: 'Rimuovi condizione',
|
||||||
|
add_condition: 'Aggiungi condizione',
|
||||||
|
are_you_sure_: 'Sei sicuro?',
|
||||||
|
sign_yourself: 'Firma te stesso',
|
||||||
|
set_signing_date: 'Imposta data di firma',
|
||||||
|
signing_date: 'Data di firma',
|
||||||
|
send: 'Invia',
|
||||||
|
remove: 'Rimuovi',
|
||||||
|
edit: 'Modifica',
|
||||||
|
settings: 'Impostazioni',
|
||||||
|
up: 'Su',
|
||||||
|
down: 'Giù',
|
||||||
|
checked: 'Selezionato',
|
||||||
|
save: 'Salva',
|
||||||
|
cancel: 'Annulla',
|
||||||
|
any: 'Qualsiasi',
|
||||||
|
drawn: 'Disegnato',
|
||||||
|
formula: 'Formula',
|
||||||
|
typed: 'Digitato',
|
||||||
|
draw_field_on_the_document: 'Disegnare un campo sul documento',
|
||||||
|
click_to_upload: 'Clicca per caricare',
|
||||||
|
or_drag_and_drop_files: 'o trascina e rilascia i file',
|
||||||
|
uploading: 'Caricamento in corso',
|
||||||
|
processing_: 'Elaborazione...',
|
||||||
|
add_pdf_documents_or_images: 'Aggiungi documenti PDF o immagini',
|
||||||
|
add_documents_or_images: 'Aggiungi documenti o immagini',
|
||||||
|
required: 'Obbligatorio',
|
||||||
|
default_value: 'Valore predefinito',
|
||||||
|
format: 'Formato',
|
||||||
|
read_only: 'Sola lettura',
|
||||||
|
page: 'Pagina',
|
||||||
|
draw_new_area: 'Disegna nuova area',
|
||||||
|
copy_to_all_pages: 'Copia in tutte le pagine',
|
||||||
|
add_option: 'Aggiungi opzione',
|
||||||
|
option: 'Opzione',
|
||||||
|
condition: 'Condizione',
|
||||||
|
first_party: 'Prima parte',
|
||||||
|
second_party: 'Seconda parte',
|
||||||
|
third_party: 'Terza parte',
|
||||||
|
fourth_party: 'Quarta parte',
|
||||||
|
fifth_party: 'Quinta parte',
|
||||||
|
sixth_party: 'Sesta parte',
|
||||||
|
seventh_party: 'Settima parte',
|
||||||
|
eighth_party: 'Ottava parte',
|
||||||
|
ninth_party: 'Nona parte',
|
||||||
|
tenth_party: 'Decima parte',
|
||||||
|
eleventh_party: 'Undicesima parte',
|
||||||
|
twelfth_party: 'Dodicesima parte',
|
||||||
|
thirteenth_party: 'Tredicesima parte',
|
||||||
|
fourteenth_party: 'Quattordicesima parte',
|
||||||
|
fifteenth_party: 'Quindicesima parte',
|
||||||
|
sixteenth_party: 'Sedicesima parte',
|
||||||
|
seventeenth_party: 'Diciassettesima parte',
|
||||||
|
eighteenth_party: 'Diciottesima parte',
|
||||||
|
nineteenth_party: 'Diciannovesima parte',
|
||||||
|
twentieth_party: 'Ventesima parte',
|
||||||
|
draw: 'Disegna',
|
||||||
|
add: 'Aggiungi',
|
||||||
|
or_add_field_without_drawing: 'Oppure aggiungi campo senza disegno',
|
||||||
|
text: 'Testo',
|
||||||
|
number: 'Numero',
|
||||||
|
signature: 'Firma',
|
||||||
|
initials: 'Iniziali',
|
||||||
|
date: 'Data',
|
||||||
|
image: 'Immagine',
|
||||||
|
file: 'File',
|
||||||
|
select: 'Seleziona',
|
||||||
|
checkbox: 'Checkbox',
|
||||||
|
multiple: 'Multiplo',
|
||||||
|
radio: 'Radio',
|
||||||
|
cells: 'Celle',
|
||||||
|
stamp: 'Timbro',
|
||||||
|
payment: 'Pagamento',
|
||||||
|
phone: 'Telefono',
|
||||||
|
text_field: 'Campo di Testo',
|
||||||
|
signature_field: 'Campo di Firma',
|
||||||
|
initials_field: 'Campo di Iniziali',
|
||||||
|
date_field: 'Campo Data',
|
||||||
|
number_field: 'Campo Numero',
|
||||||
|
image_field: 'Campo Immagine',
|
||||||
|
file_field: 'Campo File',
|
||||||
|
select_field: 'Campo di Selezione',
|
||||||
|
checkbox_field: 'Campo di Checkbox',
|
||||||
|
multiple_field: 'Campo Selezione Multipla',
|
||||||
|
radio_field: 'Campo di Gruppo Radio',
|
||||||
|
cells_field: 'Campo Celle',
|
||||||
|
stamp_field: 'Campo Timbro',
|
||||||
|
payment_field: 'Campo Pagamento',
|
||||||
|
phone_field: 'Campo Telefono',
|
||||||
|
draw_a_text_field_on_the_page_with_a_mouse: 'Disegna un campo di testo sulla pagina con il mouse',
|
||||||
|
drag_and_drop_any_other_field_type_on_the_page: 'Trascina e rilascia qualsiasi altro tipo di campo sulla pagina',
|
||||||
|
click_on_the_field_type_above_to_start_drawing_it: 'Clicca sul tipo di campo sopra per iniziare a disegnarlo',
|
||||||
|
please_draw_fields_to_prepare_the_document: 'Per favore, disegna i campi per preparare il documento.',
|
||||||
|
only_pdf_and_images_are_supported: 'Sono supportati solo PDF e immagini.',
|
||||||
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Sblocca il campo numero di telefono verificato tramite SMS con un piano a pagamento. Usa il campo di testo per numeri di telefono senza verifica.',
|
||||||
|
available_only_in_pro: 'Disponibile solo in Pro',
|
||||||
|
failed_to_download_files: 'Impossibile scaricare i file',
|
||||||
|
signature_is_too_small_please_redraw: 'La firma è troppo piccola. Ridisegnala per favore.',
|
||||||
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Aggiungi campi per {submitter_name} o rimuovi {submitter_name} se non necessario.',
|
||||||
|
draw_field: 'Disegna il campo {field}',
|
||||||
|
replace: 'Sostituisci',
|
||||||
|
uploading_: 'Caricamento in corso...',
|
||||||
|
add_document: 'Aggiungi',
|
||||||
|
none: 'Nessuno',
|
||||||
|
ssn: 'SSN',
|
||||||
|
ein: 'EIN',
|
||||||
|
email: 'Email',
|
||||||
|
url: 'URL',
|
||||||
|
zip: 'CAP',
|
||||||
|
custom: 'Personalizzato',
|
||||||
|
numbers_only: 'Solo numeri',
|
||||||
|
letters_only: 'Solo lettere',
|
||||||
|
regexp_validation: 'Validazione regexp',
|
||||||
|
enter_pdf_password: 'Inserisci password PDF',
|
||||||
|
wrong_password: 'Password errata',
|
||||||
|
currency: 'Valuta',
|
||||||
|
save_and_preview: 'Salva e Anteprima',
|
||||||
|
preferences: 'Preferenze',
|
||||||
|
available_in_pro: 'Disponibile in Pro',
|
||||||
|
some_fields_are_missing_in_the_formula: 'Alcuni campi mancano nella formula.',
|
||||||
|
learn_more: 'Scopri di più'
|
||||||
|
}
|
||||||
|
|
||||||
|
const pt = {
|
||||||
|
editable: 'Editável',
|
||||||
|
search_field: 'Campo de busca',
|
||||||
|
field_not_found: 'Campo não encontrado',
|
||||||
|
clear: 'Limpar',
|
||||||
|
type_value: 'Digite valor',
|
||||||
|
add_all_required_fields_to_continue: 'Adicione todos os campos obrigatórios para continuar',
|
||||||
|
uploaded_pdf_contains_form_fields_keep_or_remove_them: 'O PDF carregado contém campos. Manter ou removê-los?',
|
||||||
|
keep: 'Manter',
|
||||||
|
align: 'Alinhar',
|
||||||
|
left: 'Esquerda',
|
||||||
|
heading: 'Cabeçalho',
|
||||||
|
validation: 'Validação',
|
||||||
|
add_blank_page: 'Adicionar página em branco',
|
||||||
|
right: 'Direita',
|
||||||
|
center: 'Centro',
|
||||||
|
with_logo: 'Com logotipo',
|
||||||
|
description: 'Descrição',
|
||||||
|
display_title: 'Título de exibição',
|
||||||
|
signing_date: 'Data da Assinatura',
|
||||||
|
unchecked: 'Não marcado',
|
||||||
|
price: 'Preço',
|
||||||
|
equal: 'Igual',
|
||||||
|
not_equal: 'Não é igual',
|
||||||
|
contains: 'Contém',
|
||||||
|
does_not_contain: 'Não contém',
|
||||||
|
not_empty: 'Não vazio',
|
||||||
|
empty: 'Vazio',
|
||||||
|
add_condition: 'Adicionar condição',
|
||||||
|
select_field_: 'Selecionar campo...',
|
||||||
|
select_value_: 'Selecionar valor...',
|
||||||
|
remove_condition: 'Remover condição',
|
||||||
|
condition: 'Condição',
|
||||||
|
formula: 'Fórmula',
|
||||||
|
edit: 'Editar',
|
||||||
|
settings: 'Configurações',
|
||||||
|
up: 'Para cima',
|
||||||
|
down: 'Para baixo',
|
||||||
|
set_signing_date: 'Definir data de assinatura',
|
||||||
|
are_you_sure_: 'Tem certeza?',
|
||||||
|
sign_yourself: 'Assine você mesmo',
|
||||||
|
checked: 'Marcado',
|
||||||
|
send: 'Enviar',
|
||||||
|
remove: 'Remover',
|
||||||
|
save: 'Salvar',
|
||||||
|
cancel: 'Cancelar',
|
||||||
|
or_add_field_without_drawing: 'Ou adicione campo sem desenhar',
|
||||||
|
draw_field_on_the_document: 'Desenhar um campo no documento',
|
||||||
|
click_to_upload: 'Clique para enviar',
|
||||||
|
or_drag_and_drop_files: 'ou arraste e solte arquivos',
|
||||||
|
uploading: 'Carregando',
|
||||||
|
processing_: 'Processando...',
|
||||||
|
add_pdf_documents_or_images: 'Adicionar documentos PDF ou imagens',
|
||||||
|
add_documents_or_images: 'Adicionar documentos ou imagens',
|
||||||
|
required: 'Obrigatório',
|
||||||
|
default_value: 'Valor padrão',
|
||||||
|
format: 'Formato',
|
||||||
|
read_only: 'Somente leitura',
|
||||||
|
page: 'Página',
|
||||||
|
draw_new_area: 'Desenhar nova área',
|
||||||
|
copy_to_all_pages: 'Copiar para todas as páginas',
|
||||||
|
add_option: 'Adicionar opção',
|
||||||
|
option: 'Opção',
|
||||||
|
first_party: 'Primeira Parte',
|
||||||
|
second_party: 'Segunda Parte',
|
||||||
|
third_party: 'Terceira Parte',
|
||||||
|
fourth_party: 'Quarta Parte',
|
||||||
|
fifth_party: 'Quinta Parte',
|
||||||
|
sixth_party: 'Sexta Parte',
|
||||||
|
seventh_party: 'Sétima Parte',
|
||||||
|
eighth_party: 'Oitava Parte',
|
||||||
|
ninth_party: 'Nona Parte',
|
||||||
|
tenth_party: 'Décima Parte',
|
||||||
|
eleventh_party: 'Décima Primeira Parte',
|
||||||
|
twelfth_party: 'Décima Segunda Parte',
|
||||||
|
thirteenth_party: 'Décima Terceira Parte',
|
||||||
|
fourteenth_party: 'Décima Quarta Parte',
|
||||||
|
fifteenth_party: 'Décima Quinta Parte',
|
||||||
|
sixteenth_party: 'Décima Sexta Parte',
|
||||||
|
seventeenth_party: 'Décima Sétima Parte',
|
||||||
|
eighteenth_party: 'Décima Oitava Parte',
|
||||||
|
nineteenth_party: 'Décima Nona Parte',
|
||||||
|
twentieth_party: 'Vigésima Parte',
|
||||||
|
draw: 'Desenhar',
|
||||||
|
add: 'Adicionar',
|
||||||
|
text: 'Texto',
|
||||||
|
signature: 'Assinatura',
|
||||||
|
initials: 'Rúbrica',
|
||||||
|
date: 'Data',
|
||||||
|
number: 'Número',
|
||||||
|
image: 'Imagem',
|
||||||
|
file: 'Arquivo',
|
||||||
|
select: 'Selecionar',
|
||||||
|
checkbox: 'Caixa',
|
||||||
|
multiple: 'Múltiplo',
|
||||||
|
radio: 'Rádio',
|
||||||
|
cells: 'Células',
|
||||||
|
stamp: 'Carimbo',
|
||||||
|
payment: 'Pagamento',
|
||||||
|
phone: 'Telefone',
|
||||||
|
text_field: 'Campo de Texto',
|
||||||
|
signature_field: 'Campo de Assinatura',
|
||||||
|
initials_field: 'Campo de Rúbrica',
|
||||||
|
date_field: 'Campo de Data',
|
||||||
|
number_field: 'Campo de Número',
|
||||||
|
image_field: 'Campo de Imagem',
|
||||||
|
file_field: 'Campo de Arquivo',
|
||||||
|
select_field: 'Campo de Seleção',
|
||||||
|
checkbox_field: 'Campo de Caixa',
|
||||||
|
multiple_field: 'Campo de Opção Múltipla',
|
||||||
|
radio_field: 'Campo de Grupo Rádio',
|
||||||
|
cells_field: 'Campo de Células',
|
||||||
|
stamp_field: 'Campo de Carimbo',
|
||||||
|
payment_field: 'Campo de Pagamento',
|
||||||
|
phone_field: 'Campo de Telefone',
|
||||||
|
draw_a_text_field_on_the_page_with_a_mouse: 'Desenhar um campo de texto na página com o mouse',
|
||||||
|
drag_and_drop_any_other_field_type_on_the_page: 'Arraste e solte qualquer outro tipo de campo na página',
|
||||||
|
click_on_the_field_type_above_to_start_drawing_it: 'Clique no tipo de campo acima para começar a desenhá-lo',
|
||||||
|
please_draw_fields_to_prepare_the_document: 'Por favor, desenhe os campos para preparar o documento.',
|
||||||
|
only_pdf_and_images_are_supported: 'Apenas PDFs e imagens são suportados.',
|
||||||
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Desbloqueie o campo de número de telefone verificado por SMS com um plano pago. Use o campo de texto para números de telefone sem verificação.',
|
||||||
|
available_only_in_pro: 'Disponível apenas no Pro',
|
||||||
|
failed_to_download_files: 'Falha ao baixar arquivos',
|
||||||
|
signature_is_too_small_please_redraw: 'A assinatura é muito pequena. Por favor, redesenhe.',
|
||||||
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Adicione campos para {submitter_name} ou remova {submitter_name} se não for necessário.',
|
||||||
|
draw_field: 'Desenhar campo {field}',
|
||||||
|
replace: 'Substituir',
|
||||||
|
uploading_: 'Carregando...',
|
||||||
|
add_document: 'Enviar',
|
||||||
|
any: 'Qualquer',
|
||||||
|
drawn: 'Desenhado',
|
||||||
|
typed: 'Digitado',
|
||||||
|
none: 'Nenhum',
|
||||||
|
ssn: 'SSN',
|
||||||
|
ein: 'EIN',
|
||||||
|
email: 'Email',
|
||||||
|
url: 'URL',
|
||||||
|
zip: 'ZIP',
|
||||||
|
custom: 'Personalizado',
|
||||||
|
numbers_only: 'Somente números',
|
||||||
|
letters_only: 'Somente letras',
|
||||||
|
regexp_validation: 'Validação de expressão regular',
|
||||||
|
enter_pdf_password: 'Digite a senha do PDF',
|
||||||
|
wrong_password: 'Senha incorreta',
|
||||||
|
currency: 'Moeda',
|
||||||
|
save_and_preview: 'Salvar e Pré-visualizar',
|
||||||
|
preferences: 'Preferências',
|
||||||
|
available_in_pro: 'Disponível no Pro',
|
||||||
|
some_fields_are_missing_in_the_formula: 'Faltam alguns campos na fórmula.',
|
||||||
|
learn_more: 'Saiba mais'
|
||||||
|
}
|
||||||
|
|
||||||
|
const fr = {
|
||||||
|
editable: 'Éditable',
|
||||||
|
search_field: 'Champ de recherche',
|
||||||
|
field_not_found: 'Champ non trouvé',
|
||||||
|
clear: 'Effacer',
|
||||||
|
type_value: 'Tapez la valeur',
|
||||||
|
add_all_required_fields_to_continue: 'Ajoutez tous les champs obligatoires pour continuer',
|
||||||
|
uploaded_pdf_contains_form_fields_keep_or_remove_them: 'Le PDF téléchargé contient des champs. Les conserver ou les supprimer?',
|
||||||
|
keep: 'Conserver',
|
||||||
|
align: 'Aligner',
|
||||||
|
left: 'Gauche',
|
||||||
|
heading: 'En-tête',
|
||||||
|
validation: 'Validation',
|
||||||
|
add_blank_page: 'Ajouter une page blanche',
|
||||||
|
right: 'Droite',
|
||||||
|
add_condition: 'Ajouter une condition',
|
||||||
|
center: 'Centre',
|
||||||
|
with_logo: 'Avec logo',
|
||||||
|
description: 'Description',
|
||||||
|
display_title: "Titre d'affichage",
|
||||||
|
unchecked: 'Non coché',
|
||||||
|
price: 'Prix',
|
||||||
|
equal: 'Égal',
|
||||||
|
not_equal: 'Non égal',
|
||||||
|
contains: 'Contient',
|
||||||
|
signing_date: 'Date de signature',
|
||||||
|
does_not_contain: 'Ne contient pas',
|
||||||
|
not_empty: 'Non vide',
|
||||||
|
empty: 'Vide',
|
||||||
|
select_field_: 'Sélectionner un champ...',
|
||||||
|
select_value_: 'Sélectionner une valeur...',
|
||||||
|
remove_condition: 'Supprimer la condition',
|
||||||
|
condition: 'Condition',
|
||||||
|
formula: 'Formule',
|
||||||
|
edit: 'Éditer',
|
||||||
|
settings: 'Paramètres',
|
||||||
|
up: 'Haut',
|
||||||
|
down: 'Bas',
|
||||||
|
set_signing_date: 'Définir la date de signature',
|
||||||
|
are_you_sure_: 'Êtes-vous sûr?',
|
||||||
|
sign_yourself: 'Signez-vous',
|
||||||
|
checked: 'Coché',
|
||||||
|
send: 'Envoyer',
|
||||||
|
remove: 'Supprimer',
|
||||||
|
save: 'Enregistrer',
|
||||||
|
cancel: 'Annuler',
|
||||||
|
draw_field_on_the_document: 'Dessiner un champ sur le document',
|
||||||
|
click_to_upload: 'Cliquez pour télécharger',
|
||||||
|
or_drag_and_drop_files: 'ou faites glisser-déposer des fichiers',
|
||||||
|
uploading: 'Téléchargement en cours',
|
||||||
|
processing_: 'Traitement en cours...',
|
||||||
|
add_pdf_documents_or_images: 'Ajoutez des documents PDF ou des images',
|
||||||
|
add_documents_or_images: 'Ajoutez des documents ou des images',
|
||||||
|
required: 'Requis',
|
||||||
|
default_value: 'Valeur par défaut',
|
||||||
|
format: 'Format',
|
||||||
|
read_only: 'Lecture seule',
|
||||||
|
page: 'Page',
|
||||||
|
draw_new_area: 'Dessiner une nouvelle zone',
|
||||||
|
copy_to_all_pages: 'Copier sur toutes les pages',
|
||||||
|
add_option: 'Ajouter une option',
|
||||||
|
option: 'Option',
|
||||||
|
first_party: 'Première partie',
|
||||||
|
second_party: 'Deuxième partie',
|
||||||
|
third_party: 'Troisième partie',
|
||||||
|
fourth_party: 'Quatrième partie',
|
||||||
|
fifth_party: 'Cinquième partie',
|
||||||
|
sixth_party: 'Sixième partie',
|
||||||
|
seventh_party: 'Septième partie',
|
||||||
|
eighth_party: 'Huitième partie',
|
||||||
|
ninth_party: 'Neuvième partie',
|
||||||
|
tenth_party: 'Dixième partie',
|
||||||
|
eleventh_party: 'Onzième Parti',
|
||||||
|
twelfth_party: 'Douzième Parti',
|
||||||
|
thirteenth_party: 'Treizième Parti',
|
||||||
|
fourteenth_party: 'Quatorzième Parti',
|
||||||
|
fifteenth_party: 'Quinzième Parti',
|
||||||
|
sixteenth_party: 'Seizième Parti',
|
||||||
|
seventeenth_party: 'Dix-septième Parti',
|
||||||
|
eighteenth_party: 'Dix-huitième Parti',
|
||||||
|
nineteenth_party: 'Dix-Neuvième Fête',
|
||||||
|
twentieth_party: 'Vingtième Fête',
|
||||||
|
draw: 'Dessiner',
|
||||||
|
add: 'Ajouter',
|
||||||
|
or_add_field_without_drawing: 'Ou ajoutez un champ sans dessiner',
|
||||||
|
text: 'Texte',
|
||||||
|
signature: 'Signature',
|
||||||
|
initials: 'Initiales',
|
||||||
|
date: 'Date',
|
||||||
|
number: 'Numéro',
|
||||||
|
image: 'Image',
|
||||||
|
file: 'Fichier',
|
||||||
|
select: 'Choisir',
|
||||||
|
checkbox: 'Coche',
|
||||||
|
multiple: 'Multiple',
|
||||||
|
radio: 'Radio',
|
||||||
|
cells: 'Cellules',
|
||||||
|
stamp: 'Tampon',
|
||||||
|
payment: 'Paiement',
|
||||||
|
phone: 'Téléphone',
|
||||||
|
text_field: 'Champ de Texte',
|
||||||
|
signature_field: 'Champ de Signature',
|
||||||
|
initials_field: "Champ d'Initiales",
|
||||||
|
date_field: 'Champ de Date',
|
||||||
|
number_field: 'Champ de Numéro',
|
||||||
|
image_field: "Champ d'Image",
|
||||||
|
file_field: 'Champ de Fichier',
|
||||||
|
select_field: 'Champ de Choix',
|
||||||
|
checkbox_field: 'Champ de Coche',
|
||||||
|
multiple_field: 'Champ de Choix Multiple',
|
||||||
|
radio_field: 'Champ de Groupe Radio',
|
||||||
|
cells_field: 'Champ de Cellules',
|
||||||
|
stamp_field: 'Champ de Tampon',
|
||||||
|
payment_field: 'Champ de Paiement',
|
||||||
|
phone_field: 'Champ de Téléphone',
|
||||||
|
draw_a_text_field_on_the_page_with_a_mouse: 'Dessinez un champ texte sur la page avec une souris',
|
||||||
|
drag_and_drop_any_other_field_type_on_the_page: 'Glissez et déposez tout autre type de champ sur la page',
|
||||||
|
click_on_the_field_type_above_to_start_drawing_it: 'Cliquez sur le type de champ ci-dessus pour commencer à le dessiner',
|
||||||
|
please_draw_fields_to_prepare_the_document: 'Veuillez dessiner les champs pour préparer le document.',
|
||||||
|
only_pdf_and_images_are_supported: 'Seuls les PDF et les images sont pris en charge.',
|
||||||
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Débloquez le champ de numéro de téléphone vérifié par SMS avec un plan payant. Utilisez un champ texte pour les numéros de téléphone sans vérification.',
|
||||||
|
available_only_in_pro: 'Disponible uniquement en Pro',
|
||||||
|
failed_to_download_files: 'Échec du téléchargement des fichiers',
|
||||||
|
signature_is_too_small_please_redraw: 'La signature est trop petite. Veuillez la redessiner.',
|
||||||
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Veuillez ajouter des champs pour {submitter_name} ou retirer {submitter_name} si ce n\'est pas nécessaire.',
|
||||||
|
draw_field: 'Dessiner le champ {field}',
|
||||||
|
replace: 'Remplacer',
|
||||||
|
uploading_: 'Téléchargement en cours...',
|
||||||
|
add_document: 'Télécharger',
|
||||||
|
any: 'Tout',
|
||||||
|
drawn: 'Dessiné',
|
||||||
|
typed: 'Tapé',
|
||||||
|
none: 'Aucun',
|
||||||
|
ssn: 'SSN',
|
||||||
|
ein: 'EIN',
|
||||||
|
email: 'E-mail',
|
||||||
|
url: 'URL',
|
||||||
|
zip: 'ZIP',
|
||||||
|
custom: 'Personnalisé',
|
||||||
|
numbers_only: 'Chiffres uniquement',
|
||||||
|
letters_only: 'Lettres uniquement',
|
||||||
|
regexp_validation: 'Validation par expression régulière',
|
||||||
|
enter_pdf_password: 'Entrez le mot de passe PDF',
|
||||||
|
wrong_password: 'Mot de passe incorrect',
|
||||||
|
currency: 'Devise',
|
||||||
|
save_and_preview: 'Enregistrer et prévisualiser',
|
||||||
|
preferences: 'Préférences',
|
||||||
|
available_in_pro: 'Disponible en version Pro',
|
||||||
|
some_fields_are_missing_in_the_formula: 'Certains champs manquent dans la formule.',
|
||||||
|
learn_more: 'En savoir plus'
|
||||||
|
}
|
||||||
|
|
||||||
|
const de = {
|
||||||
|
editable: 'Bearbeitbar',
|
||||||
|
search_field: 'Suchfeld',
|
||||||
|
field_not_found: 'Feld nicht gefunden',
|
||||||
|
clear: 'Löschen',
|
||||||
|
type_value: 'Wert eingeben',
|
||||||
|
add_all_required_fields_to_continue: 'Fügen Sie alle erforderlichen Felder hinzu, um fortzufahren',
|
||||||
|
uploaded_pdf_contains_form_fields_keep_or_remove_them: 'Das hochgeladene PDF enthält Formularfelder. Behalten oder entfernen?',
|
||||||
|
keep: 'Behalten',
|
||||||
|
align: 'Ausrichten',
|
||||||
|
left: 'Links',
|
||||||
|
heading: 'Überschrift',
|
||||||
|
validation: 'Validierung',
|
||||||
|
add_blank_page: 'Leere Seite hinzufügen',
|
||||||
|
right: 'Rechts',
|
||||||
|
add_condition: 'Bedingung hinzufügen',
|
||||||
|
center: 'Zentriert',
|
||||||
|
with_logo: 'Mit Logo',
|
||||||
|
description: 'Beschreibung',
|
||||||
|
display_title: 'Anzeigetitel',
|
||||||
|
unchecked: 'Nicht überprüft',
|
||||||
|
price: 'Preis',
|
||||||
|
equal: 'Gleich',
|
||||||
|
not_equal: 'Ungleich',
|
||||||
|
contains: 'Enthält',
|
||||||
|
does_not_contain: 'Enthält nicht',
|
||||||
|
not_empty: 'Nicht leer',
|
||||||
|
empty: 'Leer',
|
||||||
|
signing_date: 'Signaturdatum',
|
||||||
|
select_field_: 'Feld auswählen...',
|
||||||
|
select_value_: 'Wert auswählen...',
|
||||||
|
remove_condition: 'Bedingung entfernen',
|
||||||
|
condition: 'Bedingung',
|
||||||
|
formula: 'Formel',
|
||||||
|
edit: 'Bearbeiten',
|
||||||
|
settings: 'Einstellungen',
|
||||||
|
up: 'Nach oben',
|
||||||
|
down: 'Nach unten',
|
||||||
|
set_signing_date: 'Unterschriftdatum festlegen',
|
||||||
|
are_you_sure_: 'Bist du sicher?',
|
||||||
|
sign_yourself: 'Unterschreiben Sie selbst',
|
||||||
|
checked: 'Ausgewählt',
|
||||||
|
send: 'Senden',
|
||||||
|
remove: 'Entfernen',
|
||||||
|
save: 'Speichern',
|
||||||
|
cancel: 'Abbrechen',
|
||||||
|
draw_field_on_the_document: 'Ein Feld auf dem Dokument zeichnen',
|
||||||
|
click_to_upload: 'Klicken Sie zum Hochladen',
|
||||||
|
or_drag_and_drop_files: 'oder Dateien hierher ziehen',
|
||||||
|
uploading: 'Hochladen',
|
||||||
|
processing_: 'Verarbeitung...',
|
||||||
|
add_pdf_documents_or_images: 'PDF-Dokumente oder Bilder hinzufügen',
|
||||||
|
add_documents_or_images: 'Dokumente oder Bilder hinzufügen',
|
||||||
|
required: 'Erforderlich',
|
||||||
|
default_value: 'Standardwert',
|
||||||
|
format: 'Format',
|
||||||
|
read_only: 'Nur lesen',
|
||||||
|
page: 'Seite',
|
||||||
|
draw_new_area: 'Neuen Bereich zeichnen',
|
||||||
|
copy_to_all_pages: 'Auf alle Seiten kopieren',
|
||||||
|
add_option: 'Option hinzufügen',
|
||||||
|
option: 'Option',
|
||||||
|
first_party: 'Erste Partei',
|
||||||
|
second_party: 'Zweite Partei',
|
||||||
|
third_party: 'Dritte Partei',
|
||||||
|
fourth_party: 'Vierte Partei',
|
||||||
|
fifth_party: 'Fünfte Partei',
|
||||||
|
sixth_party: 'Sechste Partei',
|
||||||
|
seventh_party: 'Siebte Partei',
|
||||||
|
eighth_party: 'Achte Partei',
|
||||||
|
ninth_party: 'Neunte Partei',
|
||||||
|
tenth_party: 'Zehnte Partei',
|
||||||
|
eleventh_party: 'Elfte Partei',
|
||||||
|
twelfth_party: 'Zwölfte Partei',
|
||||||
|
thirteenth_party: 'Dreizehnte Partei',
|
||||||
|
fourteenth_party: 'Vierzehnte Partei',
|
||||||
|
fifteenth_party: 'Fünfzehnte Partei',
|
||||||
|
sixteenth_party: 'Sechzehnte Partei',
|
||||||
|
seventeenth_party: 'Siebzehnte Partei',
|
||||||
|
eighteenth_party: 'Achtzehnte Partei',
|
||||||
|
nineteenth_party: 'Neunzehnte Party',
|
||||||
|
twentieth_party: 'Zwanzigste Party',
|
||||||
|
draw: 'Zeichnen',
|
||||||
|
add: 'Hinzufügen',
|
||||||
|
or_add_field_without_drawing: 'Oder Feld ohne Zeichnung hinzufügen',
|
||||||
|
text: 'Text',
|
||||||
|
signature: 'Unterschrift',
|
||||||
|
initials: 'Initialen',
|
||||||
|
date: 'Datum',
|
||||||
|
number: 'Nummer',
|
||||||
|
image: 'Bild',
|
||||||
|
file: 'Datei',
|
||||||
|
select: 'Auswählen',
|
||||||
|
checkbox: 'Checkbox',
|
||||||
|
multiple: 'Mehrere',
|
||||||
|
radio: 'Radio',
|
||||||
|
cells: 'Zellen',
|
||||||
|
stamp: 'Stempel',
|
||||||
|
payment: 'Zahlung',
|
||||||
|
phone: 'Telefon',
|
||||||
|
text_field: 'Textfeld',
|
||||||
|
signature_field: 'Unterschriftsfeld',
|
||||||
|
initials_field: 'Initialenfeld',
|
||||||
|
date_field: 'Datumsfeld',
|
||||||
|
number_field: 'Zahlenfeld',
|
||||||
|
image_field: 'Bildfeld',
|
||||||
|
file_field: 'Dateifeld',
|
||||||
|
select_field: 'Auswahlfeld',
|
||||||
|
checkbox_field: 'Checkbox-Feld',
|
||||||
|
multiple_field: 'Mehrfach-Auswahlfeld',
|
||||||
|
radio_field: 'Radio-Gruppenfeld',
|
||||||
|
cells_field: 'Zellenfeld',
|
||||||
|
stamp_field: 'Stempelfeld',
|
||||||
|
payment_field: 'Zahlungsfeld',
|
||||||
|
phone_field: 'Telefonfeld',
|
||||||
|
draw_a_text_field_on_the_page_with_a_mouse: 'Textfeld auf der Seite mit der Maus zeichnen',
|
||||||
|
drag_and_drop_any_other_field_type_on_the_page: 'Ziehe und lasse einen anderen Feldtyp auf die Seite fallen',
|
||||||
|
click_on_the_field_type_above_to_start_drawing_it: 'Klicke auf den Feldtyp oben, um mit dem Zeichnen zu beginnen',
|
||||||
|
please_draw_fields_to_prepare_the_document: 'Bitte zeichne Felder, um das Dokument vorzubereiten.',
|
||||||
|
only_pdf_and_images_are_supported: 'Nur PDFs und Bilder werden unterstützt.',
|
||||||
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Schalte das SMS-verifizierte Telefonnummernfeld mit einem kostenpflichtigen Plan frei. Verwende das Textfeld für Telefonnummern ohne Verifizierung.',
|
||||||
|
available_only_in_pro: 'Nur in Pro verfügbar',
|
||||||
|
failed_to_download_files: 'Fehler beim Herunterladen der Dateien',
|
||||||
|
signature_is_too_small_please_redraw: 'Die Unterschrift ist zu klein. Bitte erneut zeichnen.',
|
||||||
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Bitte füge Felder für {submitter_name} hinzu oder entferne {submitter_name}, falls nicht erforderlich.',
|
||||||
|
draw_field: 'Feld {field} zeichnen',
|
||||||
|
replace: 'Ersetzen',
|
||||||
|
uploading_: 'Hochladen...',
|
||||||
|
add_document: 'Hochladen',
|
||||||
|
any: 'Jede',
|
||||||
|
drawn: 'Gezeichnet',
|
||||||
|
typed: 'Getippt',
|
||||||
|
none: 'Keine',
|
||||||
|
ssn: 'SSN',
|
||||||
|
ein: 'EIN',
|
||||||
|
email: 'E-Mail',
|
||||||
|
url: 'URL',
|
||||||
|
zip: 'ZIP',
|
||||||
|
custom: 'Benutzerdefiniert',
|
||||||
|
numbers_only: 'Nur Zahlen',
|
||||||
|
letters_only: 'Nur Buchstaben',
|
||||||
|
regexp_validation: 'Regulärer Ausdruck Überprüfung',
|
||||||
|
enter_pdf_password: 'Geben Sie das PDF-Passwort ein',
|
||||||
|
wrong_password: 'Falsches Passwort',
|
||||||
|
currency: 'Währung',
|
||||||
|
save_and_preview: 'Speichern und Vorschau',
|
||||||
|
preferences: 'Einstellungen',
|
||||||
|
available_in_pro: 'In Pro verfügbar',
|
||||||
|
some_fields_are_missing_in_the_formula: 'Einige Felder fehlen in der Formel.',
|
||||||
|
learn_more: 'Erfahren Sie mehr'
|
||||||
|
}
|
||||||
|
|
||||||
|
export { en, es, it, pt, fr, de }
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<div v-if="selectedSheetIndex === null && spreadsheet">
|
<div v-if="selectedSheetIndex === null && spreadsheet">
|
||||||
<form @submit.prevent="[selectedSheetIndex = $refs.selectWorksheet.value, buildDefaultMappings()]">
|
<form @submit.prevent="[selectedSheetIndex = $refs.selectWorksheet.value, buildDefaultMappings()]">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
Select Worksheet
|
{{ t('select_worksheet') }}
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
ref="selectWorksheet"
|
ref="selectWorksheet"
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<button class="base-button mt-4 w-full">
|
<button class="base-button mt-4 w-full">
|
||||||
Open
|
{{ t('open') }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,10 +36,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="relative w-full py-2 px-2 text-sm">
|
<div class="relative w-full py-2 px-2 text-sm">
|
||||||
Recipient field
|
{{ t('recipient_field') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="relative w-full py-2 pl-4 text-sm">
|
<div class="relative w-full py-2 pl-4 text-sm">
|
||||||
Spreadsheet column
|
{{ t('spreadsheet_column') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
value=""
|
value=""
|
||||||
:selected="!mapping.field_name"
|
:selected="!mapping.field_name"
|
||||||
>
|
>
|
||||||
Select Field
|
{{ t('select_field') }}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
v-for="(field, index) in selectFieldsForSubmitter(submitter)"
|
v-for="(field, index) in selectFieldsForSubmitter(submitter)"
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
value=""
|
value=""
|
||||||
:selected="mapping.column_index == null"
|
:selected="mapping.column_index == null"
|
||||||
>
|
>
|
||||||
Select Column
|
{{ t('select_column') }}
|
||||||
</option>
|
</option>
|
||||||
<template
|
<template
|
||||||
v-for="(column, index) in columns"
|
v-for="(column, index) in columns"
|
||||||
@@ -118,8 +118,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center pl-1">
|
<div class="flex items-center pl-1">
|
||||||
<span
|
<span
|
||||||
class="tooltip tooltip-top"
|
class="tooltip tooltip-left"
|
||||||
data-tip="Remove"
|
:data-tip="t('remove')"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
:disabled="mappings.filter((m) => m.submitter_uuid === submitter.uuid).length < 2"
|
:disabled="mappings.filter((m) => m.submitter_uuid === submitter.uuid).length < 2"
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
@click.prevent="addMapping(submitter)"
|
@click.prevent="addMapping(submitter)"
|
||||||
>
|
>
|
||||||
<IconPlus class="w-4 h-4" />
|
<IconPlus class="w-4 h-4" />
|
||||||
New Field Mapping
|
{{ t('new_field_mapping') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
<div
|
<div
|
||||||
class="px-3 border-y py-2 border-base-300 text-center w-full text-sm font-semibold"
|
class="px-3 border-y py-2 border-base-300 text-center w-full text-sm font-semibold"
|
||||||
>
|
>
|
||||||
Total entries: {{ submissionsData.length }}
|
{{ t('total_entries') }}: {{ submissionsData.length }}
|
||||||
<template v-if="multitenant && submissionsData.length >= 1000">
|
<template v-if="multitenant && submissionsData.length >= 1000">
|
||||||
/ 1000
|
/ 1000
|
||||||
</template>
|
</template>
|
||||||
@@ -187,10 +187,10 @@
|
|||||||
<div
|
<div
|
||||||
class="font-medium text-lg mb-1"
|
class="font-medium text-lg mb-1"
|
||||||
>
|
>
|
||||||
Upload CSV or XLSX Spreadsheet
|
{{ t('upload_csv_or_xlsx_spreadsheet') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<span class="font-medium">Click to Upload</span> or drag and drop files.
|
<span class="font-medium">{{ t('click_to_upload') }}</span> {{ t('or_drag_and_drop_files') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -210,11 +210,11 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center mt-2">
|
<div class="text-center mt-2">
|
||||||
Or <a
|
{{ t('or') }} <a
|
||||||
:download="`${template.name}.csv`"
|
:download="`${template.name}.csv`"
|
||||||
:href="`data:text/csv;base64,${csvBase64}`"
|
:href="`data:text/csv;base64,${csvBase64}`"
|
||||||
class="link font-medium"
|
class="link font-medium"
|
||||||
>download</a> a spreadsheet to fill and import
|
>{{ t('download') }}</a> {{ t('a_sample_spreadsheet_to_fill_and_import') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -248,6 +248,11 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: ''
|
default: ''
|
||||||
|
},
|
||||||
|
i18n: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: () => ({})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
@@ -354,6 +359,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
t (key) {
|
||||||
|
return this.i18n[key] || key
|
||||||
|
},
|
||||||
onDropFiles (e) {
|
onDropFiles (e) {
|
||||||
this.uploadFile(e.dataTransfer.files[0])
|
this.uploadFile(e.dataTransfer.files[0])
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
class="absolute -top-1 left-2.5 px-1 h-4"
|
class="absolute -top-1 left-2.5 px-1 h-4"
|
||||||
style="font-size: 8px"
|
style="font-size: 8px"
|
||||||
>
|
>
|
||||||
Currency
|
{{ t('currency') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
class="absolute -top-1 left-2.5 px-1 h-4"
|
class="absolute -top-1 left-2.5 px-1 h-4"
|
||||||
style="font-size: 8px"
|
style="font-size: 8px"
|
||||||
>
|
>
|
||||||
Price
|
{{ t('price') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
href="https://www.docuseal.co/blog/accept-payments-and-request-signatures-with-ease"
|
href="https://www.docuseal.co/blog/accept-payments-and-request-signatures-with-ease"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
data-turbo="false"
|
data-turbo="false"
|
||||||
>Learn more</a>
|
>{{ t('learn_more') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<li class="mb-1">
|
<li class="mb-1">
|
||||||
<label
|
<label
|
||||||
|
|||||||
@@ -90,10 +90,10 @@ export default {
|
|||||||
})
|
})
|
||||||
} else if (resp.status === 422) {
|
} else if (resp.status === 422) {
|
||||||
resp.json().then((data) => {
|
resp.json().then((data) => {
|
||||||
if (data.error === 'PDF encrypted') {
|
if (data.status === 'pdf_encrypted') {
|
||||||
const formData = new FormData(this.$refs.form)
|
const formData = new FormData(this.$refs.form)
|
||||||
|
|
||||||
formData.append('password', prompt('Enter PDF password'))
|
formData.append('password', prompt(this.t('enter_pdf_password')))
|
||||||
|
|
||||||
this.baseFetch(`/templates/${this.templateId}/documents`, {
|
this.baseFetch(`/templates/${this.templateId}/documents`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -103,7 +103,7 @@ export default {
|
|||||||
this.$emit('success', await resp.json())
|
this.$emit('success', await resp.json())
|
||||||
this.$refs.input.value = ''
|
this.$refs.input.value = ''
|
||||||
} else {
|
} else {
|
||||||
alert('Wrong password')
|
alert(this.t('wrong_password'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ class ProcessSubmitterCompletionJob
|
|||||||
Submissions::EnsureResultGenerated.call(submitter)
|
Submissions::EnsureResultGenerated.call(submitter)
|
||||||
|
|
||||||
if is_all_completed && submitter.completed_at == submitter.submission.submitters.maximum(:completed_at)
|
if is_all_completed && submitter.completed_at == submitter.submission.submitters.maximum(:completed_at)
|
||||||
|
if submitter.submission.account.account_configs.exists?(key: AccountConfig::COMBINE_PDF_RESULT_KEY, value: true)
|
||||||
|
Submissions::GenerateCombinedAttachment.call(submitter)
|
||||||
|
end
|
||||||
|
|
||||||
Submissions::GenerateAuditTrail.call(submitter.submission)
|
Submissions::GenerateAuditTrail.call(submitter.submission)
|
||||||
|
|
||||||
enqueue_completed_emails(submitter)
|
enqueue_completed_emails(submitter)
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SendFormDeclinedWebhookRequestJob
|
||||||
|
include Sidekiq::Job
|
||||||
|
|
||||||
|
sidekiq_options queue: :webhooks
|
||||||
|
|
||||||
|
USER_AGENT = 'DocuSeal.co Webhook'
|
||||||
|
|
||||||
|
MAX_ATTEMPTS = 10
|
||||||
|
|
||||||
|
def perform(params = {})
|
||||||
|
submitter = Submitter.find(params['submitter_id'])
|
||||||
|
|
||||||
|
attempt = params['attempt'].to_i
|
||||||
|
config = Accounts.load_webhook_config(submitter.submission.account)
|
||||||
|
url = config&.value.presence
|
||||||
|
|
||||||
|
return if url.blank?
|
||||||
|
|
||||||
|
preferences = Accounts.load_webhook_preferences(submitter.submission.account)
|
||||||
|
|
||||||
|
return if preferences['form.declined'] == false
|
||||||
|
|
||||||
|
ActiveStorage::Current.url_options = Docuseal.default_url_options
|
||||||
|
|
||||||
|
resp = begin
|
||||||
|
Faraday.post(url,
|
||||||
|
{
|
||||||
|
event_type: 'form.declined',
|
||||||
|
timestamp: Time.current,
|
||||||
|
data: Submitters::SerializeForWebhook.call(submitter)
|
||||||
|
}.to_json,
|
||||||
|
**EncryptedConfig.find_or_initialize_by(account_id: config.account_id,
|
||||||
|
key: EncryptedConfig::WEBHOOK_SECRET_KEY)&.value.to_h,
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'User-Agent' => USER_AGENT)
|
||||||
|
rescue Faraday::Error
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS &&
|
||||||
|
(!Docuseal.multitenant? || submitter.account.account_configs.exists?(key: :plan))
|
||||||
|
SendFormDeclinedWebhookRequestJob.perform_in((2**attempt).minutes, {
|
||||||
|
'submitter_id' => submitter.id,
|
||||||
|
'attempt' => attempt + 1,
|
||||||
|
'last_status' => resp&.status.to_i
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,8 +4,6 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
MAX_ATTACHMENTS_SIZE = 10.megabytes
|
MAX_ATTACHMENTS_SIZE = 10.megabytes
|
||||||
SIGN_TTL = 1.hour + 20.minutes
|
SIGN_TTL = 1.hour + 20.minutes
|
||||||
|
|
||||||
DEFAULT_INVITATION_SUBJECT = 'You are invited to submit a form'
|
|
||||||
|
|
||||||
NO_REPLY_REGEXP = /no-?reply@/i
|
NO_REPLY_REGEXP = /no-?reply@/i
|
||||||
|
|
||||||
def invitation_email(submitter)
|
def invitation_email(submitter)
|
||||||
@@ -21,23 +19,27 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
|
|
||||||
@email_config = AccountConfigs.find_for_account(@current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY)
|
@email_config = AccountConfigs.find_for_account(@current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY)
|
||||||
|
|
||||||
subject =
|
|
||||||
if @email_config || @subject
|
|
||||||
ReplaceEmailVariables.call(@subject || @email_config.value['subject'], submitter:)
|
|
||||||
else
|
|
||||||
DEFAULT_INVITATION_SUBJECT
|
|
||||||
end
|
|
||||||
|
|
||||||
assign_message_metadata('submitter_invitation', @submitter)
|
assign_message_metadata('submitter_invitation', @submitter)
|
||||||
|
|
||||||
reply_to = build_submitter_reply_to(@submitter)
|
reply_to = build_submitter_reply_to(@submitter)
|
||||||
|
|
||||||
mail(
|
I18n.with_locale(@current_account.locale) do
|
||||||
to: @submitter.friendly_name,
|
subject =
|
||||||
from: from_address_for_submitter(submitter),
|
if @email_config || @subject
|
||||||
subject:,
|
ReplaceEmailVariables.call(@subject || @email_config.value['subject'], submitter:)
|
||||||
reply_to:
|
elsif @submitter.with_signature_fields?
|
||||||
)
|
I18n.t(:you_are_invited_to_sign_a_document)
|
||||||
|
else
|
||||||
|
I18n.t(:you_are_invited_to_submit_a_form)
|
||||||
|
end
|
||||||
|
|
||||||
|
mail(
|
||||||
|
to: @submitter.friendly_name,
|
||||||
|
from: from_address_for_submitter(submitter),
|
||||||
|
subject:,
|
||||||
|
reply_to:
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def completed_email(submitter, user, to: nil)
|
def completed_email(submitter, user, to: nil)
|
||||||
@@ -64,18 +66,35 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
@body = @submitter.template.preferences['completed_notification_email_body'].presence
|
@body = @submitter.template.preferences['completed_notification_email_body'].presence
|
||||||
@body ||= @email_config.value['body'] if @email_config
|
@body ||= @email_config.value['body'] if @email_config
|
||||||
|
|
||||||
subject =
|
|
||||||
if @subject.present?
|
|
||||||
ReplaceEmailVariables.call(@subject, submitter:)
|
|
||||||
else
|
|
||||||
build_completed_subject(submitter)
|
|
||||||
end
|
|
||||||
|
|
||||||
assign_message_metadata('submitter_completed', @submitter)
|
assign_message_metadata('submitter_completed', @submitter)
|
||||||
|
|
||||||
mail(from: from_address_for_submitter(submitter),
|
I18n.with_locale(@current_account.locale) do
|
||||||
to: to || (user.role == 'integration' ? user.friendly_name.sub(/\+\w+@/, '@') : user.friendly_name),
|
subject =
|
||||||
subject:)
|
ReplaceEmailVariables.call(@subject.presence || I18n.t(:template_name_has_been_completed_by_submitters),
|
||||||
|
submitter:)
|
||||||
|
|
||||||
|
mail(from: from_address_for_submitter(submitter),
|
||||||
|
to: to || normalize_user_email(user),
|
||||||
|
subject:)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def declined_email(submitter, user)
|
||||||
|
@current_account = submitter.submission.account
|
||||||
|
@submitter = submitter
|
||||||
|
@submission = submitter.submission
|
||||||
|
@user = user
|
||||||
|
|
||||||
|
assign_message_metadata('submitter_declined', @submitter)
|
||||||
|
|
||||||
|
I18n.with_locale(@current_account.locale) do
|
||||||
|
mail(from: from_address_for_submitter(submitter),
|
||||||
|
to: user.role == 'integration' ? user.friendly_name.sub(/\+\w+@/, '@') : user.friendly_name,
|
||||||
|
reply_to: @submitter.friendly_name,
|
||||||
|
subject: I18n.t(:name_declined_by_submitter,
|
||||||
|
name: @submission.template.name.truncate(20),
|
||||||
|
submitter: @submitter.name || @submitter.email || @submitter.phone))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def documents_copy_email(submitter, to: nil, sig: false)
|
def documents_copy_email(submitter, to: nil, sig: false)
|
||||||
@@ -98,21 +117,22 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
@body = @submitter.template.preferences['documents_copy_email_body'].presence
|
@body = @submitter.template.preferences['documents_copy_email_body'].presence
|
||||||
@body ||= @email_config.value['body'] if @email_config
|
@body ||= @email_config.value['body'] if @email_config
|
||||||
|
|
||||||
subject =
|
|
||||||
if @subject.present?
|
|
||||||
ReplaceEmailVariables.call(@subject, submitter:)
|
|
||||||
else
|
|
||||||
'Your document copy'
|
|
||||||
end
|
|
||||||
|
|
||||||
assign_message_metadata('submitter_documents_copy', @submitter)
|
assign_message_metadata('submitter_documents_copy', @submitter)
|
||||||
|
|
||||||
reply_to = build_submitter_reply_to(submitter)
|
reply_to = build_submitter_reply_to(submitter)
|
||||||
|
|
||||||
mail(from: from_address_for_submitter(submitter),
|
I18n.with_locale(@current_account.locale) do
|
||||||
to: to || @submitter.friendly_name,
|
subject =
|
||||||
reply_to:,
|
if @subject.present?
|
||||||
subject:)
|
ReplaceEmailVariables.call(@subject, submitter:)
|
||||||
|
else
|
||||||
|
I18n.t(:your_document_copy)
|
||||||
|
end
|
||||||
|
|
||||||
|
mail(from: from_address_for_submitter(submitter),
|
||||||
|
to: to || @submitter.friendly_name,
|
||||||
|
reply_to:,
|
||||||
|
subject:)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -127,19 +147,13 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
reply_to
|
reply_to
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_completed_subject(submitter)
|
|
||||||
submitters = submitter.submission.submitters.order(:completed_at)
|
|
||||||
.map { |e| e.name || e.email || e.phone }.join(', ')
|
|
||||||
%(#{submitter.submission.template.name} has been completed by #{submitters})
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_completed_email_attachments!(submitter, with_audit_log: true, with_documents: true)
|
def add_completed_email_attachments!(submitter, with_audit_log: true, with_documents: true)
|
||||||
documents = with_documents ? Submitters.select_attachments_for_download(submitter) : []
|
documents = with_documents ? Submitters.select_attachments_for_download(submitter) : []
|
||||||
|
|
||||||
total_size = 0
|
total_size = 0
|
||||||
audit_trail_data = nil
|
audit_trail_data = nil
|
||||||
|
|
||||||
if with_audit_log && submitter.submission.audit_trail.present?
|
if with_audit_log && submitter.submission.audit_trail.present? && documents.first&.name != 'combined_document'
|
||||||
audit_trail_data = submitter.submission.audit_trail.download
|
audit_trail_data = submitter.submission.audit_trail.download
|
||||||
|
|
||||||
total_size = audit_trail_data.size
|
total_size = audit_trail_data.size
|
||||||
@@ -163,6 +177,10 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
documents
|
documents
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def normalize_user_email(user)
|
||||||
|
user.role == 'integration' ? user.friendly_name.sub(/\+\w+@/, '@') : user.friendly_name
|
||||||
|
end
|
||||||
|
|
||||||
def add_attachments_with_size_limit(storage_attachments, current_size)
|
def add_attachments_with_size_limit(storage_attachments, current_size)
|
||||||
total_size = current_size
|
total_size = current_size
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ class UserMailer < ApplicationMailer
|
|||||||
|
|
||||||
assign_message_metadata('user_invitation', @user)
|
assign_message_metadata('user_invitation', @user)
|
||||||
|
|
||||||
mail(to: @user.friendly_name,
|
I18n.with_locale(@current_account.locale) do
|
||||||
subject: "You are invited to #{Docuseal.product_name}")
|
mail(to: @user.friendly_name,
|
||||||
|
subject: I18n.t('you_are_invited_to_product_name', product_name: Docuseal.product_name))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -39,32 +39,28 @@ class AccountConfig < ApplicationRecord
|
|||||||
FORCE_SSO_AUTH_KEY = 'force_sso_auth'
|
FORCE_SSO_AUTH_KEY = 'force_sso_auth'
|
||||||
FLATTEN_RESULT_PDF_KEY = 'flatten_result_pdf'
|
FLATTEN_RESULT_PDF_KEY = 'flatten_result_pdf'
|
||||||
WITH_SIGNATURE_ID = 'with_signature_id'
|
WITH_SIGNATURE_ID = 'with_signature_id'
|
||||||
|
WITH_AUDIT_VALUES_KEY = 'with_audit_values'
|
||||||
REQUIRE_SIGNING_REASON_KEY = 'require_signing_reason'
|
REQUIRE_SIGNING_REASON_KEY = 'require_signing_reason'
|
||||||
|
COMBINE_PDF_RESULT_KEY = 'combine_pdf_result_key'
|
||||||
|
|
||||||
DEFAULT_VALUES = {
|
DEFAULT_VALUES = {
|
||||||
SUBMITTER_INVITATION_EMAIL_KEY => {
|
SUBMITTER_INVITATION_EMAIL_KEY => lambda {
|
||||||
'subject' => 'You are invited to submit a form',
|
{
|
||||||
'body' => "Hi there,\n\n" \
|
'subject' => I18n.t(:you_are_invited_to_sign_a_document),
|
||||||
"You have been invited to submit the \"{{template.name}}\" form.\n\n" \
|
'body' => I18n.t(:submitter_invitation_email_sign_body)
|
||||||
"{{submitter.link}}\n\n" \
|
}
|
||||||
"Please contact us by replying to this email if you didn't request this.\n\n" \
|
|
||||||
"Thanks,\n" \
|
|
||||||
'{{account.name}}'
|
|
||||||
},
|
},
|
||||||
SUBMITTER_COMPLETED_EMAIL_KEY => {
|
SUBMITTER_COMPLETED_EMAIL_KEY => lambda {
|
||||||
'subject' => '{{template.name}} has been completed by {{submission.submitters}}',
|
{
|
||||||
'body' => "Hi,\n\n" \
|
'subject' => I18n.t(:template_name_has_been_completed_by_submitters),
|
||||||
"\"{{template.name}}\" form has been completed by {{submission.submitters}}\n\n" \
|
'body' => I18n.t(:submitter_completed_email_body)
|
||||||
'{{submission.link}}'
|
}
|
||||||
},
|
},
|
||||||
SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY => {
|
SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY => lambda {
|
||||||
'subject' => 'Your document copy',
|
{
|
||||||
'body' => "Hi there,\n\n" \
|
'subject' => I18n.t(:your_document_copy),
|
||||||
"Please check the copy of your \"{{template.name}}\" submission in the email attachments.\n" \
|
'body' => I18n.t(:submitter_documents_copy_email_body)
|
||||||
"Alternatively, you can download your copy using:\n\n" \
|
}
|
||||||
"{{documents.link}}\n\n" \
|
|
||||||
"Thanks,\n" \
|
|
||||||
'{{account.name}}'
|
|
||||||
}
|
}
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
|||||||
@@ -86,4 +86,10 @@ class Submission < ApplicationRecord
|
|||||||
ActiveStorage::Blob.proxy_url(audit_trail.blob)
|
ActiveStorage::Blob.proxy_url(audit_trail.blob)
|
||||||
end
|
end
|
||||||
alias audit_log_url audit_trail_url
|
alias audit_log_url audit_trail_url
|
||||||
|
|
||||||
|
def combined_document_url
|
||||||
|
return if combined_document.blank?
|
||||||
|
|
||||||
|
ActiveStorage::Blob.proxy_url(combined_document.blob)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -47,7 +47,9 @@ class SubmissionEvent < ApplicationRecord
|
|||||||
phone_verified: 'phone_verified',
|
phone_verified: 'phone_verified',
|
||||||
start_form: 'start_form',
|
start_form: 'start_form',
|
||||||
view_form: 'view_form',
|
view_form: 'view_form',
|
||||||
|
invite_party: 'invite_party',
|
||||||
complete_form: 'complete_form',
|
complete_form: 'complete_form',
|
||||||
|
decline_form: 'decline_form',
|
||||||
api_complete_form: 'api_complete_form'
|
api_complete_form: 'api_complete_form'
|
||||||
}, scope: false
|
}, scope: false
|
||||||
|
|
||||||
|
|||||||
+21
-2
@@ -6,6 +6,7 @@
|
|||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# completed_at :datetime
|
# completed_at :datetime
|
||||||
|
# declined_at :datetime
|
||||||
# email :string
|
# email :string
|
||||||
# ip :string
|
# ip :string
|
||||||
# metadata :text not null
|
# metadata :text not null
|
||||||
@@ -59,7 +60,9 @@ class Submitter < ApplicationRecord
|
|||||||
scope :completed, -> { where.not(completed_at: nil) }
|
scope :completed, -> { where.not(completed_at: nil) }
|
||||||
|
|
||||||
def status
|
def status
|
||||||
if completed_at?
|
if declined_at?
|
||||||
|
'declined'
|
||||||
|
elsif completed_at?
|
||||||
'completed'
|
'completed'
|
||||||
elsif opened_at?
|
elsif opened_at?
|
||||||
'opened'
|
'opened'
|
||||||
@@ -82,7 +85,23 @@ class Submitter < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def first_name
|
||||||
|
name&.split(/\s+/, 2)&.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def last_name
|
||||||
|
name&.split(/\s+/, 2)&.last
|
||||||
|
end
|
||||||
|
|
||||||
def status_event_at
|
def status_event_at
|
||||||
completed_at || opened_at || sent_at || created_at
|
declined_at || completed_at || opened_at || sent_at || created_at
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_signature_fields?
|
||||||
|
@with_signature_fields ||= begin
|
||||||
|
fields = submission.template_fields || template.fields
|
||||||
|
signature_field_types = %w[signature initials]
|
||||||
|
fields.any? { |f| f['submitter_uuid'] == uuid && signature_field_types.include?(f['type']) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -46,7 +46,7 @@ class Template < ApplicationRecord
|
|||||||
attribute :preferences, :string, default: -> { {} }
|
attribute :preferences, :string, default: -> { {} }
|
||||||
attribute :fields, :string, default: -> { [] }
|
attribute :fields, :string, default: -> { [] }
|
||||||
attribute :schema, :string, default: -> { [] }
|
attribute :schema, :string, default: -> { [] }
|
||||||
attribute :submitters, :string, default: -> { [{ name: DEFAULT_SUBMITTER_NAME, uuid: SecureRandom.uuid }] }
|
attribute :submitters, :string, default: -> { [{ name: I18n.t(:first_party), uuid: SecureRandom.uuid }] }
|
||||||
attribute :slug, :string, default: -> { SecureRandom.base58(14) }
|
attribute :slug, :string, default: -> { SecureRandom.base58(14) }
|
||||||
attribute :source, :string, default: 'native'
|
attribute :source, :string, default: 'native'
|
||||||
|
|
||||||
|
|||||||
@@ -1,51 +1,55 @@
|
|||||||
<div class="flex flex-wrap space-y-4 md:flex-nowrap md:space-y-0">
|
<div class="flex flex-wrap space-y-4 md:flex-nowrap md:space-y-0">
|
||||||
<%= render 'shared/settings_nav' %>
|
<%= render 'shared/settings_nav' %>
|
||||||
<div class="flex-grow max-w-xl mx-auto">
|
<div class="flex-grow max-w-xl mx-auto">
|
||||||
<h1 class="text-4xl font-bold mb-4">Account</h1>
|
<h1 class="text-4xl font-bold mb-4">
|
||||||
|
<%= t('account') %>
|
||||||
|
</h1>
|
||||||
<%= form_for '', url: settings_account_path, method: :patch, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
<%= form_for '', url: settings_account_path, method: :patch, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
||||||
<%= fields_for current_account do |ff| %>
|
<%= fields_for current_account do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :name, 'Company Name', class: 'label' %>
|
<%= ff.label :name, t('company_name'), class: 'label' %>
|
||||||
<%= ff.text_field :name, required: true, class: 'base-input', dir: 'auto' %>
|
<%= ff.text_field :name, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid md:grid-cols-2 gap-4">
|
<div class="grid md:grid-cols-2 gap-4">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :timezone, class: 'label' %>
|
<%= ff.label :timezone, t('time_zone'), class: 'label' %>
|
||||||
<%= ff.select :timezone, nil, {}, class: 'base-select' do %>
|
<%= ff.select :timezone, nil, {}, class: 'base-select' do %>
|
||||||
<%= time_zone_options_for_select(current_account.timezone) %>
|
<%= time_zone_options_for_select(current_account.timezone) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :locale, 'Time format', class: 'label' %>
|
<%= ff.label :locale, t('language'), class: 'label' %>
|
||||||
<%= ff.select :locale, options_for_select(controller.class::LOCALE_OPTIONS.invert, current_account.locale), {}, class: 'base-select' %>
|
<%= ff.select :locale, options_for_select(AccountsController::LOCALE_OPTIONS.invert, current_account.locale), {}, class: 'base-select' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% encrypted_config = @encrypted_config || EncryptedConfig.find_or_initialize_by(account: current_account, key: EncryptedConfig::APP_URL_KEY) %>
|
<% encrypted_config = @encrypted_config || EncryptedConfig.find_or_initialize_by(account: current_account, key: EncryptedConfig::APP_URL_KEY) %>
|
||||||
<% if !Docuseal.multitenant? && can?(:manage, encrypted_config) && !current_account.testing? %>
|
<% if !Docuseal.multitenant? && can?(:manage, encrypted_config) && !current_account.testing? && ENV['APP_URL'].blank? %>
|
||||||
<%= fields_for encrypted_config do |ff| %>
|
<%= fields_for encrypted_config do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :value, 'App URL', class: 'label' %>
|
<%= ff.label :value, t('app_url'), class: 'label' %>
|
||||||
<%= ff.text_field :value, autocomplete: 'off', class: 'base-input' %>
|
<%= ff.text_field :value, autocomplete: 'off', class: 'base-input' %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if can?(:update, current_account) %>
|
<% if can?(:update, current_account) %>
|
||||||
<div class="form-control pt-2">
|
<div class="form-control pt-2">
|
||||||
<%= f.button button_title(title: 'Update', disabled_with: 'Updating'), class: 'base-button' %>
|
<%= f.button button_title(title: t('update'), disabled_with: t('updating')), class: 'base-button' %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if can?(:manage, AccountConfig) %>
|
<% if can?(:manage, AccountConfig) %>
|
||||||
<div class="px-1 mt-8">
|
<div class="px-1 mt-8">
|
||||||
<h2 class="text-2xl font-bold mb-2">Preferences</h2>
|
<h2 class="text-2xl font-bold mb-2">
|
||||||
|
<%= t('preferences') %>
|
||||||
|
</h2>
|
||||||
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::FORCE_MFA) %>
|
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::FORCE_MFA) %>
|
||||||
<% if can?(:manage, account_config) %>
|
<% if can?(:manage, account_config) %>
|
||||||
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between py-2.5">
|
<div class="flex items-center justify-between py-2.5">
|
||||||
<span>
|
<span>
|
||||||
Force 2FA with Authenticator App
|
<%= t('force_2fa_with_authenticator_app') %>
|
||||||
</span>
|
</span>
|
||||||
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
||||||
</div>
|
</div>
|
||||||
@@ -57,7 +61,7 @@
|
|||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between py-2.5">
|
<div class="flex items-center justify-between py-2.5">
|
||||||
<span>
|
<span>
|
||||||
Add signature ID to the documents
|
<%= t('add_signature_id_to_the_documents') %>
|
||||||
</span>
|
</span>
|
||||||
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
||||||
</div>
|
</div>
|
||||||
@@ -69,7 +73,7 @@
|
|||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between py-2.5">
|
<div class="flex items-center justify-between py-2.5">
|
||||||
<span>
|
<span>
|
||||||
Require signing reason
|
<%= t('require_signing_reason') %>
|
||||||
</span>
|
</span>
|
||||||
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
||||||
</div>
|
</div>
|
||||||
@@ -81,7 +85,7 @@
|
|||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between py-2.5">
|
<div class="flex items-center justify-between py-2.5">
|
||||||
<span>
|
<span>
|
||||||
Allow typed text signatures
|
<%= t('allow_typed_text_signatures') %>
|
||||||
</span>
|
</span>
|
||||||
<%= f.check_box :value, class: 'toggle', checked: account_config.value != false, onchange: 'this.form.requestSubmit()' %>
|
<%= f.check_box :value, class: 'toggle', checked: account_config.value != false, onchange: 'this.form.requestSubmit()' %>
|
||||||
</div>
|
</div>
|
||||||
@@ -93,7 +97,7 @@
|
|||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between py-2.5">
|
<div class="flex items-center justify-between py-2.5">
|
||||||
<span>
|
<span>
|
||||||
Allow to resubmit completed forms
|
<%= t('allow_to_resubmit_completed_forms') %>
|
||||||
</span>
|
</span>
|
||||||
<%= f.check_box :value, class: 'toggle', checked: account_config.value != false, onchange: 'this.form.requestSubmit()' %>
|
<%= f.check_box :value, class: 'toggle', checked: account_config.value != false, onchange: 'this.form.requestSubmit()' %>
|
||||||
</div>
|
</div>
|
||||||
@@ -105,7 +109,7 @@
|
|||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between py-2.5">
|
<div class="flex items-center justify-between py-2.5">
|
||||||
<span>
|
<span>
|
||||||
Remember and pre-fill signatures
|
<%= t('remember_and_pre_fill_signatures') %>
|
||||||
</span>
|
</span>
|
||||||
<%= f.check_box :value, class: 'toggle', checked: account_config.value != false, onchange: 'this.form.requestSubmit()' %>
|
<%= f.check_box :value, class: 'toggle', checked: account_config.value != false, onchange: 'this.form.requestSubmit()' %>
|
||||||
</div>
|
</div>
|
||||||
@@ -117,7 +121,19 @@
|
|||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between py-2.5">
|
<div class="flex items-center justify-between py-2.5">
|
||||||
<span>
|
<span>
|
||||||
Require authentication for file download links
|
<%= t('require_authentication_for_file_download_links') %>
|
||||||
|
</span>
|
||||||
|
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::COMBINE_PDF_RESULT_KEY) %>
|
||||||
|
<% if can?(:manage, account_config) %>
|
||||||
|
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
||||||
|
<%= f.hidden_field :key %>
|
||||||
|
<div class="flex items-center justify-between py-2.5">
|
||||||
|
<span>
|
||||||
|
<%= t('combine_completed_documents_and_audit_log') %>
|
||||||
</span>
|
</span>
|
||||||
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
<%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %>
|
||||||
</div>
|
</div>
|
||||||
@@ -128,8 +144,10 @@
|
|||||||
<%= render 'integrations' %>
|
<%= render 'integrations' %>
|
||||||
<% if can?(:manage, current_account) && Docuseal.multitenant? && true_user == current_user %>
|
<% if can?(:manage, current_account) && Docuseal.multitenant? && true_user == current_user %>
|
||||||
<div class="px-1 mt-8">
|
<div class="px-1 mt-8">
|
||||||
<h2 class="text-2xl font-bold mb-2">Danger Zone</h2>
|
<h2 class="text-2xl font-bold mb-2">
|
||||||
<%= button_to button_title(title: 'Delete my account'), settings_account_path, class: 'btn btn-outline btn-error block', data: { turbo_confirm: 'Schedule account for deletion?' }, method: :delete, id: :account_delete_button %>
|
<%= t('danger_zone') %>
|
||||||
|
</h2>
|
||||||
|
<%= button_to button_title(title: t('delete_my_account')), settings_account_path, class: 'btn btn-outline btn-error block', data: { turbo_confirm: t('schedule_account_for_deletion_') }, method: :delete, id: :account_delete_button %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<div class="flex flex-wrap space-y-4 md:flex-nowrap md:space-y-0 md:space-x-10">
|
<div class="flex flex-wrap space-y-4 md:flex-nowrap md:space-y-0 md:space-x-10">
|
||||||
<%= render 'shared/settings_nav' %>
|
<%= render 'shared/settings_nav' %>
|
||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<div class="flex justify-between">
|
<div class="flex flex-col gap-2 md:flex-row md:justify-between md:items-end mb-4">
|
||||||
<h1 class="text-4xl font-bold mb-4">API</h1>
|
<h1 class="text-4xl font-bold">API</h1>
|
||||||
<%= render 'shared/test_mode_toggle' %>
|
<%= render 'shared/test_mode_toggle' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="card bg-base-200">
|
<div class="card bg-base-200">
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
<div class="flex flex-col md:flex-row gap-4">
|
<div class="flex flex-col md:flex-row gap-4">
|
||||||
<div class="flex w-full space-x-4">
|
<div class="flex w-full space-x-4">
|
||||||
<input id="api_key" type="text" value="<%= current_user.access_token.token %>" class="input font-mono input-bordered w-full" autocomplete="off" readonly>
|
<input id="api_key" type="text" value="<%= current_user.access_token.token %>" class="input font-mono input-bordered w-full" autocomplete="off" readonly>
|
||||||
<%= render 'shared/clipboard_copy', icon: 'copy', text: current_user.access_token.token, class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy', copied_title: 'Copied' %>
|
<%= render 'shared/clipboard_copy', icon: 'copy', text: current_user.access_token.token, class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: t('copy'), copied_title: t('copied') %>
|
||||||
</div>
|
</div>
|
||||||
<%= button_to button_title(title: 'Rotate', disabled_with: 'Rotate', icon: svg_icon('reload', class: 'w-6 h-6')), settings_api_index_path, class: 'white-button w-full', data: { turbo_confirm: 'Remove existing API token and generated a new one. Are you sure?' } %>
|
<%= button_to button_title(title: t('rotate'), disabled_with: t('rotate'), icon: svg_icon('reload', class: 'w-6 h-6')), settings_api_index_path, class: 'white-button w-full', data: { turbo_confirm: t('remove_existing_api_token_and_generated_a_new_one_are_you_sure_') } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<input type="checkbox">
|
<input type="checkbox">
|
||||||
<div class="collapse-title text-xl font-medium">
|
<div class="collapse-title text-xl font-medium">
|
||||||
<div>
|
<div>
|
||||||
Request signature, multiple submitters with default values
|
<%= t('request_signature_multiple_submitters_with_default_values') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<div class="badge badge-warning badge-lg">POST</div>
|
<div class="badge badge-warning badge-lg">POST</div>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
]
|
]
|
||||||
}'<% end.to_str %>
|
}'<% end.to_str %>
|
||||||
<span class="top-0 right-0 absolute">
|
<span class="top-0 right-0 absolute">
|
||||||
<%= render 'shared/clipboard_copy', icon: 'copy', text:, class: 'btn btn-ghost text-white', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy', copied_title: 'Copied' %>
|
<%= render 'shared/clipboard_copy', icon: 'copy', text:, class: 'btn btn-ghost text-white', icon_class: 'w-6 h-6 text-white', copy_title: t('copy'), copied_title: t('copied') %>
|
||||||
</span>
|
</span>
|
||||||
<pre data-prefix="$"><code class="overflow-hidden w-full"><%= text %></code></pre>
|
<pre data-prefix="$"><code class="overflow-hidden w-full"><%= text %></code></pre>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
<input type="checkbox">
|
<input type="checkbox">
|
||||||
<div class="collapse-title text-xl font-medium">
|
<div class="collapse-title text-xl font-medium">
|
||||||
<div>
|
<div>
|
||||||
Request signature, single submitter
|
<%= t('request_signature_single_submitter') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<div class="badge badge-warning badge-lg">POST</div>
|
<div class="badge badge-warning badge-lg">POST</div>
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
"emails": "<%= current_user.email.sub('@', '+test@') %>, <%= current_user.email.sub('@', '+test2@') %>"
|
"emails": "<%= current_user.email.sub('@', '+test@') %>, <%= current_user.email.sub('@', '+test2@') %>"
|
||||||
}'<% end.to_str %>
|
}'<% end.to_str %>
|
||||||
<span class="top-0 right-0 absolute">
|
<span class="top-0 right-0 absolute">
|
||||||
<%= render 'shared/clipboard_copy', icon: 'copy', text:, class: 'btn btn-ghost text-white', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy', copied_title: 'Copied' %>
|
<%= render 'shared/clipboard_copy', icon: 'copy', text:, class: 'btn btn-ghost text-white', icon_class: 'w-6 h-6 text-white', copy_title: t('copy'), copied_title: t('copied') %>
|
||||||
</span>
|
</span>
|
||||||
<pre data-prefix="$"><code class="overflow-hidden w-full"><%= text %></code></pre>
|
<pre data-prefix="$"><code class="overflow-hidden w-full"><%= text %></code></pre>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<input type="checkbox">
|
<input type="checkbox">
|
||||||
<div class="collapse-title text-xl font-medium">
|
<div class="collapse-title text-xl font-medium">
|
||||||
<div>
|
<div>
|
||||||
Template details
|
<%= t('template_details') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<div class="badge badge-info badge-lg">GET</div>
|
<div class="badge badge-info badge-lg">GET</div>
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
<% text = capture do %>curl '<%= api_template_url(current_account.templates&.last || 1) %>' \
|
<% text = capture do %>curl '<%= api_template_url(current_account.templates&.last || 1) %>' \
|
||||||
--header 'X-Auth-Token: <%= current_user.access_token.token %>'<% end.to_str %>
|
--header 'X-Auth-Token: <%= current_user.access_token.token %>'<% end.to_str %>
|
||||||
<span class="top-0 right-0 absolute">
|
<span class="top-0 right-0 absolute">
|
||||||
<%= render 'shared/clipboard_copy', icon: 'copy', text:, class: 'btn btn-ghost text-white', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy', copied_title: 'Copied' %>
|
<%= render 'shared/clipboard_copy', icon: 'copy', text:, class: 'btn btn-ghost text-white', icon_class: 'w-6 h-6 text-white', copy_title: t('copy'), copied_title: t('copied') %>
|
||||||
</span>
|
</span>
|
||||||
<pre data-prefix="$"><code class="overflow-hidden w-full"><%= text %></code></pre>
|
<pre data-prefix="$"><code class="overflow-hidden w-full"><%= text %></code></pre>
|
||||||
</div>
|
</div>
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<%= link_to 'Open Full API Reference', "#{Docuseal::PRODUCT_URL}/docs/api", class: 'btn btn-warning text-base mt-4 px-8', target: '_blank', rel: 'noopener' %>
|
<%= link_to t('open_full_api_reference'), "#{Docuseal::PRODUCT_URL}/docs/api", class: 'btn btn-warning text-base mt-4 px-8', target: '_blank', rel: 'noopener' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<form action="<%= root_path %>" method="get" class="bg-base-200 px-1.5 rounded-xl py-1 whitespace-nowrap">
|
<form action="<%= root_path %>" method="get" class="bg-base-200 px-1.5 rounded-xl py-1 whitespace-nowrap">
|
||||||
<toggle-cookies data-value="templates" data-key="dashboard_view" class="sm:tooltip tooltip-top" data-tip="Templates">
|
<toggle-cookies data-value="templates" data-key="dashboard_view" class="sm:tooltip tooltip-top" data-tip="<%= t('templates') %>">
|
||||||
<button class="<%= local_assigns[:selected] == 'submissions' ? 'btn !border !rounded-lg btn-square !p-0 !btn-sm !h-8 !w-9' : 'btn btn-neutral !rounded-lg btn-square !p-0 hover:text-neutral-300 !btn-sm !h-8 !w-9 disabled:btn-neutral' %>">
|
<button class="<%= local_assigns[:selected] == 'submissions' ? 'btn !border !rounded-lg btn-square !p-0 !btn-sm !h-8 !w-9' : 'btn btn-neutral !rounded-lg btn-square !p-0 hover:text-neutral-300 !btn-sm !h-8 !w-9 disabled:btn-neutral' %>">
|
||||||
<%= svg_icon('layout_grid', class: 'w-6 h-6 stroke-2') %>
|
<%= svg_icon('layout_grid', class: 'w-6 h-6 stroke-2') %>
|
||||||
</button>
|
</button>
|
||||||
</toggle-cookies>
|
</toggle-cookies>
|
||||||
<toggle-cookies data-value="submissions" data-key="dashboard_view" class="sm:tooltip tooltip-top" data-tip="Submissions">
|
<toggle-cookies data-value="submissions" data-key="dashboard_view" class="sm:tooltip tooltip-top" data-tip="<%= t('submissions') %>">
|
||||||
<button class="<%= local_assigns[:selected] == 'submissions' ? 'btn btn-neutral !rounded-lg btn-square !p-0 hover:text-neutral-300 !btn-sm !h-8 !w-9' : 'btn !border !rounded-lg btn-square !p-0 !btn-sm !h-8 !w-9 disabled:btn-neutral' %>">
|
<button class="<%= local_assigns[:selected] == 'submissions' ? 'btn btn-neutral !rounded-lg btn-square !p-0 hover:text-neutral-300 !btn-sm !h-8 !w-9' : 'btn !border !rounded-lg btn-square !p-0 !btn-sm !h-8 !w-9 disabled:btn-neutral' %>">
|
||||||
<%= svg_icon('layout_list', class: 'w-6 h-6 stroke-2') %>
|
<%= svg_icon('layout_list', class: 'w-6 h-6 stroke-2') %>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
<div class="max-w-lg mx-auto px-2">
|
<div class="max-w-lg mx-auto px-2">
|
||||||
<h1 class="text-4xl font-bold text-center mt-8">Change your password</h1>
|
<h1 class="text-4xl font-bold text-center mt-8">
|
||||||
|
<%= t('change_your_password') %>
|
||||||
|
</h1>
|
||||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put, class: 'space-y-6' }) do |f| %>
|
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put, class: 'space-y-6' }) do |f| %>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<%= render 'devise/shared/error_messages', resource: %>
|
<%= render 'devise/shared/error_messages', resource: %>
|
||||||
<%= f.hidden_field :reset_password_token %>
|
<%= f.hidden_field :reset_password_token %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :password, 'New password', class: 'label' %>
|
<%= f.label :password, t('new_password'), class: 'label' %>
|
||||||
<%= f.password_field :password, autofocus: true, autocomplete: 'new-password', class: 'base-input' %>
|
<%= f.password_field :password, autofocus: true, autocomplete: 'new-password', class: 'base-input' %>
|
||||||
<% if @minimum_password_length %>
|
<% if @minimum_password_length %>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="label-text">(<%= @minimum_password_length %> characters minimum)</span>
|
<span class="label-text">(<%= t('minimum_password_length_characters_minimum', minimum_password_length: @minimum_password_length) %>)</span>
|
||||||
</label>
|
</label>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :password_confirmation, 'Confirm new password', class: 'label' %>
|
<%= f.label :password_confirmation, t('confirm_new_password'), class: 'label' %>
|
||||||
<%= f.password_field :password_confirmation, autocomplete: 'new-password', class: 'base-input' %>
|
<%= f.password_field :password_confirmation, autocomplete: 'new-password', class: 'base-input' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.button button_title(title: 'Change my password', disabled_with: 'Changing password'), class: 'base-button' %>
|
<%= f.button button_title(title: t('change_my_password'), disabled_with: t('changing_password')), class: 'base-button' %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
<div class="max-w-lg mx-auto px-2">
|
<div class="max-w-lg mx-auto px-2">
|
||||||
<h1 class="text-4xl font-bold text-center mt-8">Forgot your password?</h1>
|
<h1 class="text-4xl font-bold text-center mt-8">
|
||||||
|
<%= t('forgot_your_password_') %>
|
||||||
|
</h1>
|
||||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post, class: 'space-y-6' }) do |f| %>
|
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post, class: 'space-y-6' }) do |f| %>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<%= render 'devise/shared/error_messages', resource: %>
|
<%= render 'devise/shared/error_messages', resource: %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :email, class: 'label' %>
|
<%= f.label :email, t(:email), class: 'label' %>
|
||||||
<%= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'base-input' %>
|
<%= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'base-input' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.button button_title(title: 'Reset password', disabled_with: 'Resetting password'), class: 'base-button' %>
|
<%= f.button button_title(title: t('reset_password'), disabled_with: t('resetting_password')), class: 'base-button' %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
Loaded 100 of 258 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user