Merge from docusealco/wip
This commit is contained in:
@@ -12,7 +12,7 @@ jobs:
|
|||||||
- name: Install Ruby
|
- name: Install Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.4.2
|
ruby-version: 4.0.1
|
||||||
- name: Cache gems
|
- name: Cache gems
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
- name: Install Ruby
|
- name: Install Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.4.2
|
ruby-version: 4.0.1
|
||||||
- name: Cache gems
|
- name: Cache gems
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 20.9.0
|
node-version: 20.19.0
|
||||||
- name: Cache directory path
|
- name: Cache directory path
|
||||||
id: yarn-cache-dir-path
|
id: yarn-cache-dir-path
|
||||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
- name: Install Ruby
|
- name: Install Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.4.2
|
ruby-version: 4.0.1
|
||||||
- name: Cache gems
|
- name: Cache gems
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@@ -132,11 +132,11 @@ jobs:
|
|||||||
- name: Install Ruby
|
- name: Install Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.4.2
|
ruby-version: 4.0.1
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 20.9.0
|
node-version: 20.19.0
|
||||||
- name: Install Chrome
|
- name: Install Chrome
|
||||||
uses: browser-actions/setup-chrome@latest
|
uses: browser-actions/setup-chrome@latest
|
||||||
with:
|
with:
|
||||||
|
|||||||
+8
-2
@@ -1,4 +1,4 @@
|
|||||||
require:
|
plugins:
|
||||||
- rubocop-performance
|
- rubocop-performance
|
||||||
- rubocop-rails
|
- rubocop-rails
|
||||||
- rubocop-rspec
|
- rubocop-rspec
|
||||||
@@ -10,7 +10,7 @@ AllCops:
|
|||||||
- node_modules/**/*
|
- node_modules/**/*
|
||||||
- bin/*
|
- bin/*
|
||||||
- vendor/**/*
|
- vendor/**/*
|
||||||
TargetRubyVersion: '3.3'
|
TargetRubyVersion: '4.0'
|
||||||
SuggestExtensions: false
|
SuggestExtensions: false
|
||||||
|
|
||||||
Metrics/BlockLength:
|
Metrics/BlockLength:
|
||||||
@@ -100,3 +100,9 @@ Rails/ApplicationController:
|
|||||||
|
|
||||||
Rails/Output:
|
Rails/Output:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/StrongParametersExpect:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/RedirectBackOrTo:
|
||||||
|
Enabled: false
|
||||||
|
|||||||
+5
-7
@@ -1,4 +1,4 @@
|
|||||||
FROM ruby:3.4.2-alpine AS download
|
FROM ruby:4.0.1-alpine AS download
|
||||||
|
|
||||||
WORKDIR /fonts
|
WORKDIR /fonts
|
||||||
|
|
||||||
@@ -9,14 +9,14 @@ RUN apk --no-cache add fontforge wget && \
|
|||||||
wget https://cdn.jsdelivr.net/gh/notofonts/notofonts.github.io/fonts/NotoSansSymbols2/hinted/ttf/NotoSansSymbols2-Regular.ttf && \
|
wget https://cdn.jsdelivr.net/gh/notofonts/notofonts.github.io/fonts/NotoSansSymbols2/hinted/ttf/NotoSansSymbols2-Regular.ttf && \
|
||||||
wget https://github.com/Maxattax97/gnu-freefont/raw/master/ttf/FreeSans.ttf && \
|
wget https://github.com/Maxattax97/gnu-freefont/raw/master/ttf/FreeSans.ttf && \
|
||||||
wget https://github.com/impallari/DancingScript/raw/master/OFL.txt && \
|
wget https://github.com/impallari/DancingScript/raw/master/OFL.txt && \
|
||||||
wget -O /model.onnx "https://github.com/docusealco/fields-detection/releases/download/2.1.0/model_704_int8.onnx" && \
|
wget -O /model.onnx "https://github.com/docusealco/fields-detection/releases/download/2.0.0/model_704_int8.onnx" && \
|
||||||
wget -O pdfium-linux.tgz "https://github.com/docusealco/pdfium-binaries/releases/latest/download/pdfium-linux-$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/').tgz" && \
|
wget -O pdfium-linux.tgz "https://github.com/docusealco/pdfium-binaries/releases/latest/download/pdfium-linux-$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/').tgz" && \
|
||||||
mkdir -p /pdfium-linux && \
|
mkdir -p /pdfium-linux && \
|
||||||
tar -xzf pdfium-linux.tgz -C /pdfium-linux
|
tar -xzf pdfium-linux.tgz -C /pdfium-linux
|
||||||
|
|
||||||
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.4.2-alpine AS webpack
|
FROM ruby:4.0.1-alpine AS webpack
|
||||||
|
|
||||||
ENV RAILS_ENV=production
|
ENV RAILS_ENV=production
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
@@ -42,7 +42,7 @@ COPY ./app/views ./app/views
|
|||||||
|
|
||||||
RUN echo "gem 'shakapacker'" > Gemfile && ./bin/shakapacker
|
RUN echo "gem 'shakapacker'" > Gemfile && ./bin/shakapacker
|
||||||
|
|
||||||
FROM ruby:3.4.2-alpine AS app
|
FROM ruby:4.0.1-alpine AS app
|
||||||
|
|
||||||
ENV RAILS_ENV=production
|
ENV RAILS_ENV=production
|
||||||
ENV BUNDLE_WITHOUT="development:test"
|
ENV BUNDLE_WITHOUT="development:test"
|
||||||
@@ -51,7 +51,7 @@ ENV OPENSSL_CONF=/etc/openssl_legacy.cnf
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN apk add --no-cache sqlite-dev libpq-dev mariadb-dev vips-dev yaml-dev redis libheif vips-heif gcompat ttf-freefont && mkdir /fonts && rm /usr/share/fonts/freefont/FreeSans.otf
|
RUN apk add --no-cache sqlite-dev libpq-dev mariadb-dev vips-dev yaml-dev redis libheif vips-heif gcompat ttf-freefont onnxruntime && mkdir /fonts && rm /usr/share/fonts/freefont/FreeSans.otf
|
||||||
|
|
||||||
RUN addgroup -g 2000 docuseal && adduser -u 2000 -G docuseal -s /bin/sh -D -h /home/docuseal docuseal
|
RUN addgroup -g 2000 docuseal && adduser -u 2000 -G docuseal -s /bin/sh -D -h /home/docuseal docuseal
|
||||||
|
|
||||||
@@ -71,8 +71,6 @@ COPY --chown=docuseal:docuseal ./Gemfile ./Gemfile.lock ./
|
|||||||
|
|
||||||
RUN apk add --no-cache build-base && bundle install && apk del --no-cache build-base && rm -rf ~/.bundle /usr/local/bundle/cache && ruby -e "puts Dir['/usr/local/bundle/**/{spec,rdoc,resources/shared,resources/collation,resources/locales}']" | xargs rm -rf && ln -sf /usr/lib/libonnxruntime.so.1 $(ruby -e "print Dir[Gem::Specification.find_by_name('onnxruntime').gem_dir + '/vendor/*.so'].first")
|
RUN apk add --no-cache build-base && bundle install && apk del --no-cache build-base && rm -rf ~/.bundle /usr/local/bundle/cache && ruby -e "puts Dir['/usr/local/bundle/**/{spec,rdoc,resources/shared,resources/collation,resources/locales}']" | xargs rm -rf && ln -sf /usr/lib/libonnxruntime.so.1 $(ruby -e "print Dir[Gem::Specification.find_by_name('onnxruntime').gem_dir + '/vendor/*.so'].first")
|
||||||
|
|
||||||
RUN echo 'https://dl-cdn.alpinelinux.org/alpine/edge/main' >> /etc/apk/repositories && echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories && apk add --no-cache onnxruntime
|
|
||||||
|
|
||||||
COPY --chown=docuseal:docuseal ./bin ./bin
|
COPY --chown=docuseal:docuseal ./bin ./bin
|
||||||
COPY --chown=docuseal:docuseal ./app ./app
|
COPY --chown=docuseal:docuseal ./app ./app
|
||||||
COPY --chown=docuseal:docuseal ./config ./config
|
COPY --chown=docuseal:docuseal ./config ./config
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
ruby '3.4.2'
|
ruby '4.0.1'
|
||||||
|
|
||||||
gem 'arabic-letter-connector', require: 'arabic-letter-connector/logic'
|
gem 'arabic-letter-connector', require: false
|
||||||
gem 'aws-sdk-s3', require: false
|
gem 'aws-sdk-s3', require: false
|
||||||
gem 'aws-sdk-secretsmanager', require: false
|
gem 'aws-sdk-secretsmanager', require: false
|
||||||
gem 'azure-storage-blob', require: false
|
gem 'azure-blob', require: false
|
||||||
gem 'bootsnap', require: false
|
gem 'bootsnap', require: false
|
||||||
gem 'cancancan'
|
gem 'cancancan'
|
||||||
gem 'csv'
|
gem 'csv', require: false
|
||||||
gem 'csv-safe'
|
gem 'csv-safe', require: false
|
||||||
gem 'devise'
|
gem 'devise'
|
||||||
gem 'devise-two-factor'
|
gem 'devise-two-factor'
|
||||||
gem 'dotenv', require: false
|
gem 'dotenv', require: false
|
||||||
@@ -21,12 +21,12 @@ gem 'faraday-follow_redirects'
|
|||||||
gem 'google-cloud-storage', require: false
|
gem 'google-cloud-storage', require: false
|
||||||
gem 'hexapdf'
|
gem 'hexapdf'
|
||||||
gem 'image_processing'
|
gem 'image_processing'
|
||||||
gem 'jwt'
|
gem 'jwt', require: false
|
||||||
gem 'lograge'
|
gem 'lograge'
|
||||||
gem 'mysql2', require: false
|
gem 'mysql2', require: false
|
||||||
gem 'numo-narray'
|
gem 'numo-narray-alt', require: false
|
||||||
gem 'oj'
|
gem 'oj'
|
||||||
gem 'onnxruntime'
|
gem 'onnxruntime', require: false
|
||||||
gem 'pagy'
|
gem 'pagy'
|
||||||
gem 'pg', require: false
|
gem 'pg', require: false
|
||||||
gem 'premailer-rails'
|
gem 'premailer-rails'
|
||||||
@@ -38,9 +38,9 @@ gem 'rails_autolink'
|
|||||||
gem 'rails-i18n'
|
gem 'rails-i18n'
|
||||||
gem 'rotp'
|
gem 'rotp'
|
||||||
gem 'rouge', require: false
|
gem 'rouge', require: false
|
||||||
gem 'rqrcode'
|
gem 'rqrcode', require: false
|
||||||
gem 'ruby-vips'
|
gem 'ruby-vips'
|
||||||
gem 'rubyXL'
|
gem 'rubyXL', require: false
|
||||||
gem 'shakapacker'
|
gem 'shakapacker'
|
||||||
gem 'sidekiq'
|
gem 'sidekiq'
|
||||||
gem 'sqlite3', require: false
|
gem 'sqlite3', require: false
|
||||||
|
|||||||
+279
-284
@@ -1,29 +1,31 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (8.0.2.1)
|
action_text-trix (2.1.16)
|
||||||
actionpack (= 8.0.2.1)
|
railties
|
||||||
activesupport (= 8.0.2.1)
|
actioncable (8.1.2)
|
||||||
|
actionpack (= 8.1.2)
|
||||||
|
activesupport (= 8.1.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (8.0.2.1)
|
actionmailbox (8.1.2)
|
||||||
actionpack (= 8.0.2.1)
|
actionpack (= 8.1.2)
|
||||||
activejob (= 8.0.2.1)
|
activejob (= 8.1.2)
|
||||||
activerecord (= 8.0.2.1)
|
activerecord (= 8.1.2)
|
||||||
activestorage (= 8.0.2.1)
|
activestorage (= 8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
actionmailer (8.0.2.1)
|
actionmailer (8.1.2)
|
||||||
actionpack (= 8.0.2.1)
|
actionpack (= 8.1.2)
|
||||||
actionview (= 8.0.2.1)
|
actionview (= 8.1.2)
|
||||||
activejob (= 8.0.2.1)
|
activejob (= 8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (8.0.2.1)
|
actionpack (8.1.2)
|
||||||
actionview (= 8.0.2.1)
|
actionview (= 8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4)
|
||||||
rack-session (>= 1.0.1)
|
rack-session (>= 1.0.1)
|
||||||
@@ -31,55 +33,58 @@ GEM
|
|||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
useragent (~> 0.16)
|
useragent (~> 0.16)
|
||||||
actiontext (8.0.2.1)
|
actiontext (8.1.2)
|
||||||
actionpack (= 8.0.2.1)
|
action_text-trix (~> 2.1.15)
|
||||||
activerecord (= 8.0.2.1)
|
actionpack (= 8.1.2)
|
||||||
activestorage (= 8.0.2.1)
|
activerecord (= 8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activestorage (= 8.1.2)
|
||||||
|
activesupport (= 8.1.2)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (8.0.2.1)
|
actionview (8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
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 (8.0.2.1)
|
activejob (8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (8.0.2.1)
|
activemodel (8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
activerecord (8.0.2.1)
|
activerecord (8.1.2)
|
||||||
activemodel (= 8.0.2.1)
|
activemodel (= 8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (8.0.2.1)
|
activestorage (8.1.2)
|
||||||
actionpack (= 8.0.2.1)
|
actionpack (= 8.1.2)
|
||||||
activejob (= 8.0.2.1)
|
activejob (= 8.1.2)
|
||||||
activerecord (= 8.0.2.1)
|
activerecord (= 8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (8.0.2.1)
|
activesupport (8.1.2)
|
||||||
base64
|
base64
|
||||||
benchmark (>= 0.3)
|
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
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)
|
||||||
|
json
|
||||||
logger (>= 1.4.2)
|
logger (>= 1.4.2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
securerandom (>= 0.3)
|
securerandom (>= 0.3)
|
||||||
tzinfo (~> 2.0, >= 2.0.5)
|
tzinfo (~> 2.0, >= 2.0.5)
|
||||||
uri (>= 0.13.1)
|
uri (>= 0.13.1)
|
||||||
addressable (2.8.7)
|
addressable (2.8.8)
|
||||||
public_suffix (>= 2.0.2, < 7.0)
|
public_suffix (>= 2.0.2, < 8.0)
|
||||||
annotaterb (4.14.0)
|
annotaterb (4.20.0)
|
||||||
|
activerecord (>= 6.0.0)
|
||||||
|
activesupport (>= 6.0.0)
|
||||||
arabic-letter-connector (0.1.1)
|
arabic-letter-connector (0.1.1)
|
||||||
ast (2.4.3)
|
ast (2.4.3)
|
||||||
aws-eventstream (1.4.0)
|
aws-eventstream (1.4.0)
|
||||||
aws-partitions (1.1197.0)
|
aws-partitions (1.1209.0)
|
||||||
aws-sdk-core (3.240.0)
|
aws-sdk-core (3.241.4)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.992.0)
|
aws-partitions (~> 1, >= 1.992.0)
|
||||||
aws-sigv4 (~> 1.9)
|
aws-sigv4 (~> 1.9)
|
||||||
@@ -87,44 +92,38 @@ GEM
|
|||||||
bigdecimal
|
bigdecimal
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
logger
|
logger
|
||||||
aws-sdk-kms (1.118.0)
|
aws-sdk-kms (1.121.0)
|
||||||
aws-sdk-core (~> 3, >= 3.239.1)
|
aws-sdk-core (~> 3, >= 3.241.4)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.208.0)
|
aws-sdk-s3 (1.212.0)
|
||||||
aws-sdk-core (~> 3, >= 3.234.0)
|
aws-sdk-core (~> 3, >= 3.241.4)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-secretsmanager (1.110.0)
|
aws-sdk-secretsmanager (1.128.0)
|
||||||
aws-sdk-core (~> 3, >= 3.210.0)
|
aws-sdk-core (~> 3, >= 3.241.4)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sigv4 (1.12.1)
|
aws-sigv4 (1.12.1)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
azure-storage-blob (2.0.3)
|
azure-blob (0.8.0)
|
||||||
azure-storage-common (~> 2.0)
|
cgi
|
||||||
nokogiri (~> 1, >= 1.10.8)
|
rexml
|
||||||
azure-storage-common (2.0.4)
|
|
||||||
faraday (~> 1.0)
|
|
||||||
faraday_middleware (~> 1.0, >= 1.0.0.rc1)
|
|
||||||
net-http-persistent (~> 4.0)
|
|
||||||
nokogiri (~> 1, >= 1.10.8)
|
|
||||||
base64 (0.3.0)
|
base64 (0.3.0)
|
||||||
bcrypt (3.1.20)
|
bcrypt (3.1.21)
|
||||||
benchmark (0.4.1)
|
better_html (2.2.0)
|
||||||
better_html (2.1.1)
|
actionview (>= 7.0)
|
||||||
actionview (>= 6.0)
|
activesupport (>= 7.0)
|
||||||
activesupport (>= 6.0)
|
|
||||||
ast (~> 2.0)
|
ast (~> 2.0)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
parser (>= 2.4)
|
parser (>= 2.4)
|
||||||
smart_properties
|
smart_properties
|
||||||
bigdecimal (3.2.2)
|
bigdecimal (4.0.1)
|
||||||
bindex (0.8.1)
|
bindex (0.8.1)
|
||||||
bootsnap (1.18.4)
|
bootsnap (1.21.1)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (7.0.0)
|
brakeman (7.1.2)
|
||||||
racc
|
racc
|
||||||
builder (3.3.0)
|
builder (3.3.0)
|
||||||
bullet (8.0.0)
|
bullet (8.1.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)
|
||||||
@@ -138,28 +137,29 @@ 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)
|
||||||
|
cgi (0.5.1)
|
||||||
childprocess (5.1.0)
|
childprocess (5.1.0)
|
||||||
logger (~> 1.5)
|
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)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
concurrent-ruby (1.3.5)
|
concurrent-ruby (1.3.6)
|
||||||
connection_pool (2.5.3)
|
connection_pool (3.0.2)
|
||||||
crack (1.0.0)
|
crack (1.0.1)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
rexml
|
rexml
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
css_parser (1.21.0)
|
css_parser (1.21.1)
|
||||||
addressable
|
addressable
|
||||||
csv (3.3.2)
|
csv (3.3.5)
|
||||||
csv-safe (3.3.1)
|
csv-safe (3.3.1)
|
||||||
csv (~> 3.0)
|
csv (~> 3.0)
|
||||||
cuprite (0.15.1)
|
cuprite (0.17)
|
||||||
capybara (~> 3.0)
|
capybara (~> 3.0)
|
||||||
ferrum (~> 0.15.0)
|
ferrum (~> 0.17.0)
|
||||||
date (3.4.1)
|
date (3.5.1)
|
||||||
debug (1.10.0)
|
debug (1.11.1)
|
||||||
irb (~> 1.10)
|
irb (~> 1.10)
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
declarative (0.0.20)
|
declarative (0.0.20)
|
||||||
@@ -169,20 +169,20 @@ GEM
|
|||||||
railties (>= 4.1.0)
|
railties (>= 4.1.0)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise-two-factor (6.1.0)
|
devise-two-factor (6.3.1)
|
||||||
activesupport (>= 7.0, < 8.1)
|
activesupport (>= 7.0, < 8.2)
|
||||||
devise (~> 4.0)
|
devise (>= 4.0, < 5.0)
|
||||||
railties (>= 7.0, < 8.1)
|
railties (>= 7.0, < 8.2)
|
||||||
rotp (~> 6.0)
|
rotp (~> 6.0)
|
||||||
diff-lcs (1.5.1)
|
diff-lcs (1.6.2)
|
||||||
digest-crc (0.6.5)
|
digest-crc (0.7.0)
|
||||||
rake (>= 12.0.0, < 14.0.0)
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
docile (1.4.1)
|
docile (1.4.1)
|
||||||
dotenv (3.1.7)
|
dotenv (3.2.0)
|
||||||
drb (2.2.3)
|
drb (2.2.3)
|
||||||
email_typo (0.2.3)
|
email_typo (0.2.3)
|
||||||
erb (5.0.2)
|
erb (6.0.1)
|
||||||
erb_lint (0.7.0)
|
erb_lint (0.9.0)
|
||||||
activesupport
|
activesupport
|
||||||
better_html (>= 2.0.1)
|
better_html (>= 2.0.1)
|
||||||
parser (>= 2.7.1.4)
|
parser (>= 2.7.1.4)
|
||||||
@@ -190,117 +190,101 @@ GEM
|
|||||||
rubocop (>= 1)
|
rubocop (>= 1)
|
||||||
smart_properties
|
smart_properties
|
||||||
erubi (1.13.1)
|
erubi (1.13.1)
|
||||||
factory_bot (6.5.0)
|
factory_bot (6.5.6)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 6.1.0)
|
||||||
factory_bot_rails (6.4.4)
|
factory_bot_rails (6.5.1)
|
||||||
factory_bot (~> 6.5)
|
factory_bot (~> 6.5)
|
||||||
railties (>= 5.0.0)
|
railties (>= 6.1.0)
|
||||||
faker (3.5.1)
|
faker (3.6.0)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (1.10.4)
|
faraday (2.14.0)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-net_http (>= 2.0, < 3.5)
|
||||||
faraday-em_synchrony (~> 1.0)
|
json
|
||||||
faraday-excon (~> 1.1)
|
logger
|
||||||
faraday-httpclient (~> 1.0)
|
faraday-follow_redirects (0.5.0)
|
||||||
faraday-multipart (~> 1.0)
|
|
||||||
faraday-net_http (~> 1.0)
|
|
||||||
faraday-net_http_persistent (~> 1.0)
|
|
||||||
faraday-patron (~> 1.0)
|
|
||||||
faraday-rack (~> 1.0)
|
|
||||||
faraday-retry (~> 1.0)
|
|
||||||
ruby2_keywords (>= 0.0.4)
|
|
||||||
faraday-em_http (1.0.0)
|
|
||||||
faraday-em_synchrony (1.0.0)
|
|
||||||
faraday-excon (1.1.0)
|
|
||||||
faraday-follow_redirects (0.3.0)
|
|
||||||
faraday (>= 1, < 3)
|
faraday (>= 1, < 3)
|
||||||
faraday-httpclient (1.0.1)
|
faraday-net_http (3.4.2)
|
||||||
faraday-multipart (1.1.0)
|
net-http (~> 0.5)
|
||||||
multipart-post (~> 2.0)
|
ferrum (0.17.1)
|
||||||
faraday-net_http (1.0.2)
|
|
||||||
faraday-net_http_persistent (1.2.0)
|
|
||||||
faraday-patron (1.0.0)
|
|
||||||
faraday-rack (1.0.0)
|
|
||||||
faraday-retry (1.0.3)
|
|
||||||
faraday_middleware (1.2.1)
|
|
||||||
faraday (~> 1.0)
|
|
||||||
ferrum (0.15)
|
|
||||||
addressable (~> 2.5)
|
addressable (~> 2.5)
|
||||||
|
base64 (~> 0.2)
|
||||||
concurrent-ruby (~> 1.1)
|
concurrent-ruby (~> 1.1)
|
||||||
webrick (~> 1.7)
|
webrick (~> 1.7)
|
||||||
websocket-driver (~> 0.7)
|
websocket-driver (~> 0.7)
|
||||||
ffi (1.17.1)
|
ffi (1.17.3)
|
||||||
ffi (1.17.1-aarch64-linux-gnu)
|
ffi (1.17.3-aarch64-linux-gnu)
|
||||||
ffi (1.17.1-aarch64-linux-musl)
|
ffi (1.17.3-aarch64-linux-musl)
|
||||||
ffi (1.17.1-arm64-darwin)
|
ffi (1.17.3-arm64-darwin)
|
||||||
ffi (1.17.1-x86_64-linux-gnu)
|
ffi (1.17.3-x86_64-linux-gnu)
|
||||||
ffi (1.17.1-x86_64-linux-musl)
|
ffi (1.17.3-x86_64-linux-musl)
|
||||||
foreman (0.88.1)
|
foreman (0.90.0)
|
||||||
|
thor (~> 1.4)
|
||||||
geom2d (0.4.1)
|
geom2d (0.4.1)
|
||||||
globalid (1.2.1)
|
globalid (1.3.0)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
google-apis-core (0.15.1)
|
google-apis-core (1.0.2)
|
||||||
addressable (~> 2.5, >= 2.5.1)
|
addressable (~> 2.8, >= 2.8.7)
|
||||||
googleauth (~> 1.9)
|
faraday (~> 2.13)
|
||||||
httpclient (>= 2.8.3, < 3.a)
|
faraday-follow_redirects (~> 0.3)
|
||||||
mini_mime (~> 1.0)
|
googleauth (~> 1.14)
|
||||||
mutex_m
|
mini_mime (~> 1.1)
|
||||||
representable (~> 3.0)
|
representable (~> 3.0)
|
||||||
retriable (>= 2.0, < 4.a)
|
retriable (~> 3.1)
|
||||||
google-apis-iamcredentials_v1 (0.22.0)
|
google-apis-iamcredentials_v1 (0.26.0)
|
||||||
google-apis-core (>= 0.15.0, < 2.a)
|
google-apis-core (>= 0.15.0, < 2.a)
|
||||||
google-apis-storage_v1 (0.49.0)
|
google-apis-storage_v1 (0.59.0)
|
||||||
google-apis-core (>= 0.15.0, < 2.a)
|
google-apis-core (>= 0.15.0, < 2.a)
|
||||||
google-cloud-core (1.7.1)
|
google-cloud-core (1.8.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.2.1)
|
google-cloud-env (2.3.1)
|
||||||
|
base64 (~> 0.2)
|
||||||
faraday (>= 1.0, < 3.a)
|
faraday (>= 1.0, < 3.a)
|
||||||
google-cloud-errors (1.4.0)
|
google-cloud-errors (1.5.0)
|
||||||
google-cloud-storage (1.54.0)
|
google-cloud-storage (1.58.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
digest-crc (~> 0.4)
|
digest-crc (~> 0.4)
|
||||||
google-apis-core (~> 0.13)
|
google-apis-core (>= 0.18, < 2)
|
||||||
google-apis-iamcredentials_v1 (~> 0.18)
|
google-apis-iamcredentials_v1 (~> 0.18)
|
||||||
google-apis-storage_v1 (~> 0.38)
|
google-apis-storage_v1 (>= 0.42)
|
||||||
google-cloud-core (~> 1.6)
|
google-cloud-core (~> 1.6)
|
||||||
googleauth (~> 1.9)
|
googleauth (~> 1.9)
|
||||||
mini_mime (~> 1.0)
|
mini_mime (~> 1.0)
|
||||||
google-logging-utils (0.1.0)
|
google-logging-utils (0.2.0)
|
||||||
googleauth (1.12.2)
|
googleauth (1.16.1)
|
||||||
faraday (>= 1.0, < 3.a)
|
faraday (>= 1.0, < 3.a)
|
||||||
google-cloud-env (~> 2.2)
|
google-cloud-env (~> 2.2)
|
||||||
google-logging-utils (~> 0.1)
|
google-logging-utils (~> 0.1)
|
||||||
jwt (>= 1.4, < 3.0)
|
jwt (>= 1.4, < 4.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.2)
|
hashdiff (1.2.1)
|
||||||
hexapdf (1.4.0)
|
hexapdf (1.5.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)
|
||||||
strscan (>= 3.1.2)
|
strscan (>= 3.1.2)
|
||||||
htmlentities (4.3.4)
|
htmlentities (4.4.2)
|
||||||
httpclient (2.8.3)
|
i18n (1.14.8)
|
||||||
i18n (1.14.7)
|
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
image_processing (1.13.0)
|
image_processing (1.14.0)
|
||||||
mini_magick (>= 4.9.5, < 5)
|
mini_magick (>= 4.9.5, < 6)
|
||||||
ruby-vips (>= 2.0.17, < 3)
|
ruby-vips (>= 2.0.17, < 3)
|
||||||
io-console (0.8.1)
|
io-console (0.8.2)
|
||||||
irb (1.15.2)
|
irb (1.16.0)
|
||||||
pp (>= 0.6.0)
|
pp (>= 0.6.0)
|
||||||
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.15.0)
|
json (2.18.0)
|
||||||
jwt (2.9.3)
|
jwt (3.1.2)
|
||||||
base64
|
base64
|
||||||
language_server-protocol (3.17.0.5)
|
language_server-protocol (3.17.0.5)
|
||||||
launchy (3.0.1)
|
launchy (3.1.1)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
childprocess (~> 5.0)
|
childprocess (~> 5.0)
|
||||||
|
logger (~> 1.6)
|
||||||
letter_opener (1.10.0)
|
letter_opener (1.10.0)
|
||||||
launchy (>= 2.2, < 4)
|
launchy (>= 2.2, < 4)
|
||||||
letter_opener_web (3.0.0)
|
letter_opener_web (3.0.0)
|
||||||
@@ -315,29 +299,30 @@ GEM
|
|||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.24.1)
|
loofah (2.25.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.12.0)
|
||||||
mail (2.8.1)
|
mail (2.9.0)
|
||||||
|
logger
|
||||||
mini_mime (>= 0.1.1)
|
mini_mime (>= 0.1.1)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
marcel (1.0.4)
|
marcel (1.1.0)
|
||||||
matrix (0.4.2)
|
matrix (0.4.3)
|
||||||
method_source (1.1.0)
|
method_source (1.1.0)
|
||||||
mini_magick (4.13.2)
|
mini_magick (5.3.1)
|
||||||
|
logger
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.9)
|
minitest (6.0.1)
|
||||||
minitest (5.25.5)
|
prism (~> 1.5)
|
||||||
msgpack (1.7.5)
|
msgpack (1.8.0)
|
||||||
multi_json (1.15.0)
|
multi_json (1.19.1)
|
||||||
multipart-post (2.4.1)
|
mysql2 (0.5.7)
|
||||||
mutex_m (0.3.0)
|
bigdecimal
|
||||||
mysql2 (0.5.6)
|
net-http (0.9.1)
|
||||||
net-http-persistent (4.0.5)
|
uri (>= 0.11.1)
|
||||||
connection_pool (~> 2.2)
|
net-imap (0.6.2)
|
||||||
net-imap (0.5.9)
|
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
@@ -346,22 +331,19 @@ GEM
|
|||||||
timeout
|
timeout
|
||||||
net-smtp (0.5.1)
|
net-smtp (0.5.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.4)
|
nio4r (2.7.5)
|
||||||
nokogiri (1.18.9)
|
nokogiri (1.19.0-aarch64-linux-gnu)
|
||||||
mini_portile2 (~> 2.8.2)
|
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.9-aarch64-linux-gnu)
|
nokogiri (1.19.0-aarch64-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.9-aarch64-linux-musl)
|
nokogiri (1.19.0-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.9-arm64-darwin)
|
nokogiri (1.19.0-x86_64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.9-x86_64-linux-gnu)
|
nokogiri (1.19.0-x86_64-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.18.9-x86_64-linux-musl)
|
numo-narray-alt (0.9.13)
|
||||||
racc (~> 1.4)
|
oj (3.16.13)
|
||||||
numo-narray (0.9.2.1)
|
|
||||||
oj (3.16.11)
|
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
ostruct (>= 0.2)
|
ostruct (>= 0.2)
|
||||||
onnxruntime (0.10.1)
|
onnxruntime (0.10.1)
|
||||||
@@ -372,18 +354,25 @@ GEM
|
|||||||
ffi
|
ffi
|
||||||
onnxruntime (0.10.1-x86_64-linux)
|
onnxruntime (0.10.1-x86_64-linux)
|
||||||
ffi
|
ffi
|
||||||
openssl (3.3.0)
|
openssl (4.0.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
os (1.1.4)
|
os (1.1.4)
|
||||||
ostruct (0.6.3)
|
ostruct (0.6.3)
|
||||||
package_json (0.1.0)
|
package_json (0.2.0)
|
||||||
pagy (9.3.3)
|
pagy (43.2.8)
|
||||||
|
json
|
||||||
|
yaml
|
||||||
parallel (1.27.0)
|
parallel (1.27.0)
|
||||||
parser (3.3.9.0)
|
parser (3.3.10.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
pg (1.5.9)
|
pg (1.6.3)
|
||||||
pp (0.6.2)
|
pg (1.6.3-aarch64-linux)
|
||||||
|
pg (1.6.3-aarch64-linux-musl)
|
||||||
|
pg (1.6.3-arm64-darwin)
|
||||||
|
pg (1.6.3-x86_64-linux)
|
||||||
|
pg (1.6.3-x86_64-linux-musl)
|
||||||
|
pp (0.6.3)
|
||||||
prettyprint
|
prettyprint
|
||||||
premailer (1.27.0)
|
premailer (1.27.0)
|
||||||
addressable
|
addressable
|
||||||
@@ -393,23 +382,24 @@ GEM
|
|||||||
actionmailer (>= 3)
|
actionmailer (>= 3)
|
||||||
net-smtp
|
net-smtp
|
||||||
premailer (~> 1.7, >= 1.7.9)
|
premailer (~> 1.7, >= 1.7.9)
|
||||||
pretender (0.5.0)
|
pretender (0.6.0)
|
||||||
actionpack (>= 6.1)
|
actionpack (>= 7.1)
|
||||||
prettyprint (0.2.0)
|
prettyprint (0.2.0)
|
||||||
prism (1.5.1)
|
prism (1.8.0)
|
||||||
pry (0.15.0)
|
pry (0.16.0)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
method_source (~> 1.0)
|
method_source (~> 1.0)
|
||||||
|
reline (>= 0.6.0)
|
||||||
pry-rails (0.3.11)
|
pry-rails (0.3.11)
|
||||||
pry (>= 0.13.0)
|
pry (>= 0.13.0)
|
||||||
psych (5.2.6)
|
psych (5.3.1)
|
||||||
date
|
date
|
||||||
stringio
|
stringio
|
||||||
public_suffix (6.0.1)
|
public_suffix (7.0.2)
|
||||||
puma (6.5.0)
|
puma (7.2.0)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.8.1)
|
racc (1.8.1)
|
||||||
rack (3.2.3)
|
rack (3.2.4)
|
||||||
rack-proxy (0.7.7)
|
rack-proxy (0.7.7)
|
||||||
rack
|
rack
|
||||||
rack-session (2.1.1)
|
rack-session (2.1.1)
|
||||||
@@ -417,22 +407,22 @@ GEM
|
|||||||
rack (>= 3.0.0)
|
rack (>= 3.0.0)
|
||||||
rack-test (2.2.0)
|
rack-test (2.2.0)
|
||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rackup (2.2.1)
|
rackup (2.3.1)
|
||||||
rack (>= 3)
|
rack (>= 3)
|
||||||
rails (8.0.2.1)
|
rails (8.1.2)
|
||||||
actioncable (= 8.0.2.1)
|
actioncable (= 8.1.2)
|
||||||
actionmailbox (= 8.0.2.1)
|
actionmailbox (= 8.1.2)
|
||||||
actionmailer (= 8.0.2.1)
|
actionmailer (= 8.1.2)
|
||||||
actionpack (= 8.0.2.1)
|
actionpack (= 8.1.2)
|
||||||
actiontext (= 8.0.2.1)
|
actiontext (= 8.1.2)
|
||||||
actionview (= 8.0.2.1)
|
actionview (= 8.1.2)
|
||||||
activejob (= 8.0.2.1)
|
activejob (= 8.1.2)
|
||||||
activemodel (= 8.0.2.1)
|
activemodel (= 8.1.2)
|
||||||
activerecord (= 8.0.2.1)
|
activerecord (= 8.1.2)
|
||||||
activestorage (= 8.0.2.1)
|
activestorage (= 8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 8.0.2.1)
|
railties (= 8.1.2)
|
||||||
rails-dom-testing (2.3.0)
|
rails-dom-testing (2.3.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
minitest
|
minitest
|
||||||
@@ -440,30 +430,32 @@ GEM
|
|||||||
rails-html-sanitizer (1.6.2)
|
rails-html-sanitizer (1.6.2)
|
||||||
loofah (~> 2.21)
|
loofah (~> 2.21)
|
||||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||||
rails-i18n (8.0.1)
|
rails-i18n (8.1.0)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 8.0.0, < 9)
|
railties (>= 8.0.0, < 9)
|
||||||
rails_autolink (1.1.8)
|
rails_autolink (1.1.8)
|
||||||
actionview (> 3.1)
|
actionview (> 3.1)
|
||||||
activesupport (> 3.1)
|
activesupport (> 3.1)
|
||||||
railties (> 3.1)
|
railties (> 3.1)
|
||||||
railties (8.0.2.1)
|
railties (8.1.2)
|
||||||
actionpack (= 8.0.2.1)
|
actionpack (= 8.1.2)
|
||||||
activesupport (= 8.0.2.1)
|
activesupport (= 8.1.2)
|
||||||
irb (~> 1.13)
|
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)
|
||||||
|
tsort (>= 0.2)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.3.0)
|
rake (13.3.1)
|
||||||
rdoc (6.14.2)
|
rdoc (7.1.0)
|
||||||
erb
|
erb
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
redis-client (0.23.0)
|
tsort
|
||||||
|
redis-client (0.26.4)
|
||||||
connection_pool
|
connection_pool
|
||||||
regexp_parser (2.11.3)
|
regexp_parser (2.11.3)
|
||||||
reline (0.6.2)
|
reline (0.6.3)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
representable (3.2.0)
|
representable (3.2.0)
|
||||||
declarative (< 0.1.0)
|
declarative (< 0.1.0)
|
||||||
@@ -471,35 +463,35 @@ GEM
|
|||||||
uber (< 0.2.0)
|
uber (< 0.2.0)
|
||||||
request_store (1.7.0)
|
request_store (1.7.0)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.1.1)
|
responders (3.2.0)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 7.0)
|
||||||
railties (>= 5.2)
|
railties (>= 7.0)
|
||||||
retriable (3.1.2)
|
retriable (3.1.2)
|
||||||
rexml (3.4.4)
|
rexml (3.4.4)
|
||||||
rotp (6.3.0)
|
rotp (6.3.0)
|
||||||
rouge (4.5.2)
|
rouge (4.7.0)
|
||||||
rqrcode (2.2.0)
|
rqrcode (3.2.0)
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
rqrcode_core (~> 1.0)
|
rqrcode_core (~> 2.0)
|
||||||
rqrcode_core (1.2.0)
|
rqrcode_core (2.1.0)
|
||||||
rspec-core (3.13.2)
|
rspec-core (3.13.6)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-expectations (3.13.3)
|
rspec-expectations (3.13.5)
|
||||||
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.2)
|
rspec-mocks (3.13.7)
|
||||||
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 (7.1.0)
|
rspec-rails (8.0.2)
|
||||||
actionpack (>= 7.0)
|
actionpack (>= 7.2)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.2)
|
||||||
railties (>= 7.0)
|
railties (>= 7.2)
|
||||||
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.2)
|
rspec-support (3.13.6)
|
||||||
rubocop (1.81.1)
|
rubocop (1.82.1)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (~> 3.17.0.2)
|
language_server-protocol (~> 3.17.0.2)
|
||||||
lint_roller (~> 1.1.0)
|
lint_roller (~> 1.1.0)
|
||||||
@@ -507,86 +499,89 @@ GEM
|
|||||||
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.9.3, < 3.0)
|
regexp_parser (>= 2.9.3, < 3.0)
|
||||||
rubocop-ast (>= 1.47.1, < 2.0)
|
rubocop-ast (>= 1.48.0, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 4.0)
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
rubocop-ast (1.47.1)
|
rubocop-ast (1.49.0)
|
||||||
parser (>= 3.3.7.2)
|
parser (>= 3.3.7.2)
|
||||||
prism (~> 1.4)
|
prism (~> 1.7)
|
||||||
rubocop-performance (1.23.0)
|
rubocop-performance (1.26.1)
|
||||||
rubocop (>= 1.48.1, < 2.0)
|
lint_roller (~> 1.1)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop (>= 1.75.0, < 2.0)
|
||||||
rubocop-rails (2.27.0)
|
rubocop-ast (>= 1.47.1, < 2.0)
|
||||||
|
rubocop-rails (2.34.3)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.52.0, < 2.0)
|
rubocop (>= 1.75.0, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop-ast (>= 1.44.0, < 2.0)
|
||||||
rubocop-rspec (3.3.0)
|
rubocop-rspec (3.9.0)
|
||||||
rubocop (~> 1.61)
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (~> 1.81)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-vips (2.2.2)
|
ruby-vips (2.3.0)
|
||||||
ffi (~> 1.12)
|
ffi (~> 1.12)
|
||||||
logger
|
logger
|
||||||
ruby2_keywords (0.0.5)
|
rubyXL (3.4.35)
|
||||||
rubyXL (3.4.33)
|
|
||||||
nokogiri (>= 1.10.8)
|
nokogiri (>= 1.10.8)
|
||||||
rubyzip (>= 1.3.0)
|
rubyzip (>= 3.2.2)
|
||||||
rubyzip (2.3.2)
|
rubyzip (3.2.2)
|
||||||
securerandom (0.4.1)
|
securerandom (0.4.1)
|
||||||
semantic_range (3.1.0)
|
semantic_range (3.1.0)
|
||||||
shakapacker (8.0.2)
|
shakapacker (9.5.0)
|
||||||
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.3.7)
|
sidekiq (8.1.0)
|
||||||
connection_pool (>= 2.3.0)
|
connection_pool (>= 3.0.0)
|
||||||
logger
|
json (>= 2.16.0)
|
||||||
rack (>= 2.2.4)
|
logger (>= 1.7.0)
|
||||||
redis-client (>= 0.22.2)
|
rack (>= 3.2.0)
|
||||||
signet (0.19.0)
|
redis-client (>= 0.26.0)
|
||||||
|
signet (0.21.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
faraday (>= 0.17.5, < 3.a)
|
faraday (>= 0.17.5, < 3.a)
|
||||||
jwt (>= 1.5, < 3.0)
|
jwt (>= 1.5, < 4.0)
|
||||||
multi_json (~> 1.10)
|
multi_json (~> 1.10)
|
||||||
simplecov (0.22.0)
|
simplecov (0.22.0)
|
||||||
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.13.1)
|
simplecov-html (0.13.2)
|
||||||
simplecov_json_formatter (0.1.4)
|
simplecov_json_formatter (0.1.4)
|
||||||
smart_properties (1.17.0)
|
smart_properties (1.17.0)
|
||||||
sqlite3 (2.5.0)
|
sqlite3 (2.9.0-aarch64-linux-gnu)
|
||||||
mini_portile2 (~> 2.8.0)
|
sqlite3 (2.9.0-aarch64-linux-musl)
|
||||||
sqlite3 (2.5.0-aarch64-linux-gnu)
|
sqlite3 (2.9.0-arm64-darwin)
|
||||||
sqlite3 (2.5.0-aarch64-linux-musl)
|
sqlite3 (2.9.0-x86_64-linux-gnu)
|
||||||
sqlite3 (2.5.0-arm64-darwin)
|
sqlite3 (2.9.0-x86_64-linux-musl)
|
||||||
sqlite3 (2.5.0-x86_64-linux-gnu)
|
stringio (3.2.0)
|
||||||
sqlite3 (2.5.0-x86_64-linux-musl)
|
strip_attributes (2.0.1)
|
||||||
stringio (3.1.7)
|
|
||||||
strip_attributes (1.14.1)
|
|
||||||
activemodel (>= 3.0, < 9.0)
|
activemodel (>= 3.0, < 9.0)
|
||||||
strscan (3.1.5)
|
strscan (3.1.7)
|
||||||
thor (1.4.0)
|
thor (1.5.0)
|
||||||
timeout (0.4.3)
|
timeout (0.6.0)
|
||||||
trailblazer-option (0.1.2)
|
trailblazer-option (0.1.2)
|
||||||
turbo-rails (2.0.11)
|
tsort (0.2.0)
|
||||||
actionpack (>= 6.0.0)
|
turbo-rails (2.0.21)
|
||||||
railties (>= 6.0.0)
|
actionpack (>= 7.1.0)
|
||||||
twitter_cldr (6.12.1)
|
railties (>= 7.1.0)
|
||||||
|
twitter_cldr (6.14.0)
|
||||||
|
base64
|
||||||
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.2)
|
tzinfo-data (1.2025.3)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
uber (0.1.0)
|
uber (0.1.0)
|
||||||
unicode-display_width (3.2.0)
|
unicode-display_width (3.2.0)
|
||||||
unicode-emoji (~> 4.1)
|
unicode-emoji (~> 4.1)
|
||||||
unicode-emoji (4.1.0)
|
unicode-emoji (4.2.0)
|
||||||
uniform_notifier (1.16.0)
|
uniform_notifier (1.18.0)
|
||||||
uri (1.1.1)
|
uri (1.1.1)
|
||||||
useragent (0.16.11)
|
useragent (0.16.11)
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
@@ -596,24 +591,24 @@ 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.24.0)
|
webmock (3.26.1)
|
||||||
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.9.1)
|
webrick (1.9.2)
|
||||||
websocket-driver (0.8.0)
|
websocket-driver (0.8.0)
|
||||||
base64
|
base64
|
||||||
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.7.3)
|
yaml (0.4.0)
|
||||||
|
zeitwerk (2.7.4)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
aarch64-linux
|
aarch64-linux
|
||||||
aarch64-linux-musl
|
aarch64-linux-musl
|
||||||
arm64-darwin
|
arm64-darwin
|
||||||
ruby
|
|
||||||
x86_64-linux
|
x86_64-linux
|
||||||
x86_64-linux-musl
|
x86_64-linux-musl
|
||||||
|
|
||||||
@@ -622,7 +617,7 @@ DEPENDENCIES
|
|||||||
arabic-letter-connector
|
arabic-letter-connector
|
||||||
aws-sdk-s3
|
aws-sdk-s3
|
||||||
aws-sdk-secretsmanager
|
aws-sdk-secretsmanager
|
||||||
azure-storage-blob
|
azure-blob
|
||||||
better_html
|
better_html
|
||||||
bootsnap
|
bootsnap
|
||||||
brakeman
|
brakeman
|
||||||
@@ -650,7 +645,7 @@ DEPENDENCIES
|
|||||||
letter_opener_web
|
letter_opener_web
|
||||||
lograge
|
lograge
|
||||||
mysql2
|
mysql2
|
||||||
numo-narray
|
numo-narray-alt
|
||||||
oj
|
oj
|
||||||
onnxruntime
|
onnxruntime
|
||||||
pagy
|
pagy
|
||||||
@@ -685,7 +680,7 @@ DEPENDENCIES
|
|||||||
webmock
|
webmock
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 3.4.2p28
|
ruby 4.0.1
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.5.3
|
4.0.3
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AccountCustomFieldsController < ApplicationController
|
||||||
|
before_action :load_account_config, only: :create
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize!(:create, Template)
|
||||||
|
|
||||||
|
@account_config.update!(account_config_params)
|
||||||
|
|
||||||
|
render json: @account_config.value
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_account_config
|
||||||
|
@account_config =
|
||||||
|
AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::TEMPLATE_CUSTOM_FIELDS_KEY)
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_config_params
|
||||||
|
params.permit(
|
||||||
|
value: [[:uuid, :name, :type,
|
||||||
|
:required, :readonly, :default_value,
|
||||||
|
:title, :description,
|
||||||
|
{ preferences: {},
|
||||||
|
default_value: [],
|
||||||
|
options: [%i[value uuid]],
|
||||||
|
validation: %i[message pattern min max step],
|
||||||
|
areas: [%i[x y w h cell_w option_uuid]] }]]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
module Api
|
module Api
|
||||||
class ApiBaseController < ActionController::API
|
class ApiBaseController < ActionController::API
|
||||||
include ActiveStorage::SetCurrent
|
include ActiveStorage::SetCurrent
|
||||||
include Pagy::Backend
|
include Pagy::Method
|
||||||
|
|
||||||
DEFAULT_LIMIT = 10
|
DEFAULT_LIMIT = 10
|
||||||
MAX_LIMIT = 100
|
MAX_LIMIT = 100
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class ApplicationController < ActionController::Base
|
|||||||
BROWSER_LOCALE_REGEXP = /\A\w{2}(?:-\w{2})?/
|
BROWSER_LOCALE_REGEXP = /\A\w{2}(?:-\w{2})?/
|
||||||
|
|
||||||
include ActiveStorage::SetCurrent
|
include ActiveStorage::SetCurrent
|
||||||
include Pagy::Backend
|
include Pagy::Method
|
||||||
|
|
||||||
check_authorization unless: :devise_controller?
|
check_authorization unless: :devise_controller?
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
impersonates :user, with: ->(uuid) { User.find_by(uuid:) }
|
impersonates :user, with: ->(uuid) { User.find_by(uuid:) }
|
||||||
|
|
||||||
rescue_from Pagy::OverflowError do
|
rescue_from Pagy::RangeError do
|
||||||
redirect_to request.path
|
redirect_to request.path
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
def pagy_auto(collection, **keyword_args)
|
def pagy_auto(collection, **keyword_args)
|
||||||
if current_ability.can?(:manage, :countless)
|
if current_ability.can?(:manage, :countless)
|
||||||
pagy_countless(collection, **keyword_args)
|
pagy(:countless, collection, **keyword_args)
|
||||||
else
|
else
|
||||||
pagy(collection, **keyword_args)
|
pagy(collection, **keyword_args)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class TemplatesDetectFieldsController < ApplicationController
|
|||||||
documents = @template.schema_documents.preload(:blob)
|
documents = @template.schema_documents.preload(:blob)
|
||||||
documents = documents.where(uuid: params[:attachment_uuid]) if params[:attachment_uuid].present?
|
documents = documents.where(uuid: params[:attachment_uuid]) if params[:attachment_uuid].present?
|
||||||
|
|
||||||
page_number = params[:page].present? ? params[:page].to_i : nil
|
page_number = params[:page].presence&.to_i
|
||||||
|
|
||||||
documents.each do |document|
|
documents.each do |document|
|
||||||
io = StringIO.new(document.download)
|
io = StringIO.new(document.download)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class TimestampServerController < ApplicationController
|
|||||||
uri = Addressable::URI.parse(url)
|
uri = Addressable::URI.parse(url)
|
||||||
|
|
||||||
conn = Faraday.new(uri.origin) do |c|
|
conn = Faraday.new(uri.origin) do |c|
|
||||||
c.basic_auth(uri.user, uri.password) if uri.password.present?
|
c.request :authorization, :basic, uri.user, uri.password if uri.password.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
response = conn.post(uri.path, req.to_der,
|
response = conn.post(uri.path, req.to_der,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class WebhookSettingsController < ApplicationController
|
|||||||
|
|
||||||
@webhook_events = @webhook_events.where(status: params[:status]) if %w[success error].include?(params[:status])
|
@webhook_events = @webhook_events.where(status: params[:status]) if %w[success error].include?(params[:status])
|
||||||
|
|
||||||
@pagy, @webhook_events = pagy_countless(@webhook_events.order(id: :desc))
|
@pagy, @webhook_events = pagy(:countless, @webhook_events.order(id: :desc))
|
||||||
|
|
||||||
render :show
|
render :show
|
||||||
end
|
end
|
||||||
@@ -26,7 +26,7 @@ class WebhookSettingsController < ApplicationController
|
|||||||
|
|
||||||
@webhook_events = @webhook_events.where(status: params[:status]) if %w[success error].include?(params[:status])
|
@webhook_events = @webhook_events.where(status: params[:status]) if %w[success error].include?(params[:status])
|
||||||
|
|
||||||
@pagy, @webhook_events = pagy_countless(@webhook_events.order(id: :desc))
|
@pagy, @webhook_events = pagy(:countless, @webhook_events.order(id: :desc))
|
||||||
end
|
end
|
||||||
|
|
||||||
def new; end
|
def new; end
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
|||||||
|
|
||||||
this.app = createApp(TemplateBuilder, {
|
this.app = createApp(TemplateBuilder, {
|
||||||
template: reactive(JSON.parse(this.dataset.template)),
|
template: reactive(JSON.parse(this.dataset.template)),
|
||||||
|
customFields: reactive(JSON.parse(this.dataset.customFields || '[]')),
|
||||||
backgroundColor: '#faf7f5',
|
backgroundColor: '#faf7f5',
|
||||||
locale: this.dataset.locale,
|
locale: this.dataset.locale,
|
||||||
withPhone: this.dataset.withPhone === 'true',
|
withPhone: this.dataset.withPhone === 'true',
|
||||||
@@ -164,6 +165,7 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
|||||||
withFieldsDetection: this.dataset.withFieldsDetection === 'true',
|
withFieldsDetection: this.dataset.withFieldsDetection === 'true',
|
||||||
editable: this.dataset.editable !== 'false',
|
editable: this.dataset.editable !== 'false',
|
||||||
authenticityToken: document.querySelector('meta[name="csrf-token"]')?.content,
|
authenticityToken: document.querySelector('meta[name="csrf-token"]')?.content,
|
||||||
|
withCustomFields: true,
|
||||||
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',
|
||||||
|
|||||||
+51
-6
@@ -4,15 +4,26 @@ import { isValidSignatureCanvas } from './submission_form/validate_signature'
|
|||||||
|
|
||||||
window.customElements.define('draw-signature', class extends HTMLElement {
|
window.customElements.define('draw-signature', class extends HTMLElement {
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
const scale = 3
|
this.setCanvasSize()
|
||||||
|
|
||||||
this.canvas.width = this.canvas.parentNode.clientWidth * scale
|
|
||||||
this.canvas.height = this.canvas.parentNode.clientHeight * scale
|
|
||||||
|
|
||||||
this.canvas.getContext('2d').scale(scale, scale)
|
|
||||||
|
|
||||||
this.pad = new SignaturePad(this.canvas)
|
this.pad = new SignaturePad(this.canvas)
|
||||||
|
|
||||||
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (!this.canvas) return
|
||||||
|
|
||||||
|
const { width, height } = this.canvas
|
||||||
|
|
||||||
|
this.setCanvasSize()
|
||||||
|
|
||||||
|
if (this.canvas.width !== width || this.canvas.height !== height) {
|
||||||
|
this.redrawCanvas(width, height)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.resizeObserver.observe(this.canvas.parentNode)
|
||||||
|
|
||||||
if (this.dataset.color) {
|
if (this.dataset.color) {
|
||||||
this.pad.penColor = this.dataset.color
|
this.pad.penColor = this.dataset.color
|
||||||
}
|
}
|
||||||
@@ -57,6 +68,40 @@ window.customElements.define('draw-signature', class extends HTMLElement {
|
|||||||
this.updateSubmitButtonVisibility()
|
this.updateSubmitButtonVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disconnectedCallback () {
|
||||||
|
if (this.resizeObserver) {
|
||||||
|
this.resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setCanvasSize () {
|
||||||
|
const scale = 3
|
||||||
|
|
||||||
|
const width = this.canvas.parentNode.clientWidth
|
||||||
|
const height = this.canvas.parentNode.clientHeight
|
||||||
|
|
||||||
|
if (this.canvas.width !== width * scale || this.canvas.height !== height * scale) {
|
||||||
|
this.canvas.width = width * scale
|
||||||
|
this.canvas.height = height * scale
|
||||||
|
|
||||||
|
this.canvas.getContext('2d').scale(scale, scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
redrawCanvas (oldWidth, oldHeight) {
|
||||||
|
if (this.pad && !this.pad.isEmpty()) {
|
||||||
|
const sx = this.canvas.width / oldWidth
|
||||||
|
const sy = this.canvas.height / oldHeight
|
||||||
|
|
||||||
|
const scaledData = this.pad.toData().map((stroke) => ({
|
||||||
|
...stroke,
|
||||||
|
points: stroke.points.map((p) => ({ ...p, x: p.x * sx, y: p.y * sy }))
|
||||||
|
}))
|
||||||
|
|
||||||
|
this.pad.fromData(scaledData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateSubmitButtonVisibility () {
|
updateSubmitButtonVisibility () {
|
||||||
if (this.pad.isEmpty()) {
|
if (this.pad.isEmpty()) {
|
||||||
this.submitButton.style.display = 'none'
|
this.submitButton.style.display = 'none'
|
||||||
|
|||||||
@@ -5,17 +5,28 @@ export default targetable(class extends HTMLElement {
|
|||||||
static [target.static] = ['canvas', 'input', 'clear', 'button']
|
static [target.static] = ['canvas', 'input', 'clear', 'button']
|
||||||
|
|
||||||
async connectedCallback () {
|
async connectedCallback () {
|
||||||
const scale = 3
|
|
||||||
|
|
||||||
this.canvas.width = this.canvas.parentNode.clientWidth * scale
|
|
||||||
this.canvas.height = this.canvas.parentNode.clientHeight * scale
|
|
||||||
|
|
||||||
this.canvas.getContext('2d').scale(scale, scale)
|
|
||||||
|
|
||||||
const { default: SignaturePad } = await import('signature_pad')
|
const { default: SignaturePad } = await import('signature_pad')
|
||||||
|
|
||||||
|
this.setCanvasSize()
|
||||||
|
|
||||||
this.pad = new SignaturePad(this.canvas)
|
this.pad = new SignaturePad(this.canvas)
|
||||||
|
|
||||||
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (!this.canvas) return
|
||||||
|
|
||||||
|
const { width, height } = this.canvas
|
||||||
|
|
||||||
|
this.setCanvasSize()
|
||||||
|
|
||||||
|
if (this.canvas.width !== width || this.canvas.height !== height) {
|
||||||
|
this.redrawCanvas(width, height)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.resizeObserver.observe(this.canvas.parentNode)
|
||||||
|
|
||||||
this.clear.addEventListener('click', (e) => {
|
this.clear.addEventListener('click', (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
@@ -47,4 +58,38 @@ export default targetable(class extends HTMLElement {
|
|||||||
|
|
||||||
this.closest('form').requestSubmit()
|
this.closest('form').requestSubmit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disconnectedCallback () {
|
||||||
|
if (this.resizeObserver) {
|
||||||
|
this.resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setCanvasSize () {
|
||||||
|
const scale = 3
|
||||||
|
|
||||||
|
const width = this.canvas.parentNode.clientWidth
|
||||||
|
const height = this.canvas.parentNode.clientWidth / 2.5
|
||||||
|
|
||||||
|
if (this.canvas.width !== width * scale || this.canvas.height !== height * scale) {
|
||||||
|
this.canvas.width = width * scale
|
||||||
|
this.canvas.height = height * scale
|
||||||
|
|
||||||
|
this.canvas.getContext('2d').scale(scale, scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
redrawCanvas (oldWidth, oldHeight) {
|
||||||
|
if (this.pad && !this.pad.isEmpty()) {
|
||||||
|
const sx = this.canvas.width / oldWidth
|
||||||
|
const sy = this.canvas.height / oldHeight
|
||||||
|
|
||||||
|
const scaledData = this.pad.toData().map((stroke) => ({
|
||||||
|
...stroke,
|
||||||
|
points: stroke.points.map((p) => ({ ...p, x: p.x * sx, y: p.y * sy }))
|
||||||
|
}))
|
||||||
|
|
||||||
|
this.pad.fromData(scaledData)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
id="expand_form_button"
|
id="expand_form_button"
|
||||||
class="btn btn-neutral flex text-white absolute bottom-0 w-full mb-3 expand-form-button text-base"
|
class="btn btn-neutral flex text-white absolute bottom-0 w-full mb-3 expand-form-button text-base"
|
||||||
style="width: 96%; margin-left: 2%"
|
style="width: 96%; margin-left: 2%"
|
||||||
@click.prevent="[isFormVisible = true, scrollIntoField(currentField)]"
|
@click.prevent="[isFormVisible = true, $nextTick(() => scrollIntoField(currentField))]"
|
||||||
>
|
>
|
||||||
<template v-if="['initials', 'signature'].includes(currentField.type)">
|
<template v-if="['initials', 'signature'].includes(currentField.type)">
|
||||||
<IconWritingSign stroke-width="1.5" />
|
<IconWritingSign stroke-width="1.5" />
|
||||||
@@ -592,6 +592,18 @@ import AppearsOn from './appears_on'
|
|||||||
import i18n from './i18n'
|
import i18n from './i18n'
|
||||||
import { sanitizeUrl } from '@braintree/sanitize-url'
|
import { sanitizeUrl } from '@braintree/sanitize-url'
|
||||||
|
|
||||||
|
if (typeof URL.canParse !== 'function') {
|
||||||
|
URL.canParse = function (url, base) {
|
||||||
|
try {
|
||||||
|
const parsed = new URL(url, base)
|
||||||
|
|
||||||
|
return !!parsed
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const isEmpty = (obj) => {
|
const isEmpty = (obj) => {
|
||||||
if (obj == null) return true
|
if (obj == null) return true
|
||||||
|
|
||||||
|
|||||||
@@ -175,9 +175,7 @@
|
|||||||
v-if="isShowQr"
|
v-if="isShowQr"
|
||||||
class="top-0 bottom-0 right-0 left-0 absolute bg-base-content/10 rounded-2xl"
|
class="top-0 bottom-0 right-0 left-0 absolute bg-base-content/10 rounded-2xl"
|
||||||
>
|
>
|
||||||
<div
|
<div class="absolute top-1.5 right-1.5">
|
||||||
class="absolute top-1.5 right-1.5 md:tooltip"
|
|
||||||
>
|
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="btn btn-sm btn-circle btn-normal btn-outline"
|
class="btn btn-sm btn-circle btn-normal btn-outline"
|
||||||
@@ -448,14 +446,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => this.setCanvasSize())
|
||||||
if (this.$refs.canvas) {
|
|
||||||
this.$refs.canvas.width = this.$refs.canvas.parentNode.clientWidth * scale
|
|
||||||
this.$refs.canvas.height = this.$refs.canvas.parentNode.clientWidth * scale / 3
|
|
||||||
|
|
||||||
this.$refs.canvas.getContext('2d').scale(scale, scale)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (this.$refs.canvas) {
|
if (this.$refs.canvas) {
|
||||||
this.pad = new SignaturePad(this.$refs.canvas)
|
this.pad = new SignaturePad(this.$refs.canvas)
|
||||||
@@ -470,13 +461,10 @@ export default {
|
|||||||
this.$emit('start')
|
this.$emit('start')
|
||||||
})
|
})
|
||||||
|
|
||||||
this.intersectionObserver = new IntersectionObserver((entries, observer) => {
|
this.intersectionObserver = new IntersectionObserver((entries) => {
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
this.$refs.canvas.width = this.$refs.canvas.parentNode.clientWidth * scale
|
this.setCanvasSize()
|
||||||
this.$refs.canvas.height = this.$refs.canvas.parentNode.clientWidth * scale / 3
|
|
||||||
|
|
||||||
this.$refs.canvas.getContext('2d').scale(scale, scale)
|
|
||||||
|
|
||||||
this.intersectionObserver?.disconnect()
|
this.intersectionObserver?.disconnect()
|
||||||
}
|
}
|
||||||
@@ -484,13 +472,62 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.intersectionObserver.observe(this.$refs.canvas)
|
this.intersectionObserver.observe(this.$refs.canvas)
|
||||||
|
|
||||||
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (!this.$refs.canvas) return
|
||||||
|
|
||||||
|
const { width, height } = this.$refs.canvas
|
||||||
|
|
||||||
|
this.setCanvasSize()
|
||||||
|
|
||||||
|
if (this.$refs.canvas.width !== width || this.$refs.canvas.height !== height) {
|
||||||
|
this.redrawCanvas(width, height)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.resizeObserver.observe(this.$refs.canvas.parentNode)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeUnmount () {
|
beforeUnmount () {
|
||||||
this.intersectionObserver?.disconnect()
|
this.intersectionObserver?.disconnect()
|
||||||
|
this.resizeObserver?.disconnect()
|
||||||
this.stopCheckSignature()
|
this.stopCheckSignature()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
setCanvasSize () {
|
||||||
|
const canvas = this.$refs.canvas
|
||||||
|
|
||||||
|
if (canvas) {
|
||||||
|
const width = canvas.parentNode.clientWidth
|
||||||
|
const height = width / 3
|
||||||
|
|
||||||
|
if (canvas.width !== width * scale || canvas.height !== height * scale) {
|
||||||
|
canvas.width = width * scale
|
||||||
|
canvas.height = height * scale
|
||||||
|
|
||||||
|
canvas.getContext('2d').scale(scale, scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
redrawCanvas (oldWidth, oldHeight) {
|
||||||
|
const canvas = this.$refs.canvas
|
||||||
|
|
||||||
|
if (this.pad && !this.isTextSignature && !this.pad.isEmpty()) {
|
||||||
|
const sx = canvas.width / oldWidth
|
||||||
|
const sy = canvas.height / oldHeight
|
||||||
|
|
||||||
|
const scaledData = this.pad.toData().map((stroke) => ({
|
||||||
|
...stroke,
|
||||||
|
points: stroke.points.map((p) => ({ ...p, x: p.x * sx, y: p.y * sy }))
|
||||||
|
}))
|
||||||
|
|
||||||
|
this.pad.fromData(scaledData)
|
||||||
|
} else if (this.isTextSignature && this.$refs.textInput) {
|
||||||
|
this.updateWrittenSignature({ target: { value: this.$refs.textInput.value } })
|
||||||
|
}
|
||||||
|
},
|
||||||
remove () {
|
remove () {
|
||||||
this.$emit('update:model-value', '')
|
this.$emit('update:model-value', '')
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,9 @@
|
|||||||
@click-formula="isShowFormulaModal = true"
|
@click-formula="isShowFormulaModal = true"
|
||||||
@click-font="isShowFontModal = true"
|
@click-font="isShowFontModal = true"
|
||||||
@click-description="isShowDescriptionModal = true"
|
@click-description="isShowDescriptionModal = true"
|
||||||
|
@add-custom-field="$emit('add-custom-field')"
|
||||||
@click-condition="isShowConditionsModal = true"
|
@click-condition="isShowConditionsModal = true"
|
||||||
|
@save="save"
|
||||||
@scroll-to="[selectedAreasRef.value = [$event], $emit('scroll-to', $event)]"
|
@scroll-to="[selectedAreasRef.value = [$event], $emit('scroll-to', $event)]"
|
||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -471,7 +473,7 @@ export default {
|
|||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['start-resize', 'stop-resize', 'start-drag', 'stop-drag', 'remove', 'scroll-to'],
|
emits: ['start-resize', 'stop-resize', 'start-drag', 'stop-drag', 'remove', 'scroll-to', 'add-custom-field'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isShowFormulaModal: false,
|
isShowFormulaModal: false,
|
||||||
|
|||||||
@@ -20,8 +20,9 @@
|
|||||||
/>
|
/>
|
||||||
<DragPlaceholder
|
<DragPlaceholder
|
||||||
ref="dragPlaceholder"
|
ref="dragPlaceholder"
|
||||||
:field="fieldsDragFieldRef.value || toRaw(dragField)"
|
:field="customDragFieldRef.value || fieldsDragFieldRef.value || toRaw(dragField)"
|
||||||
:is-field="template.fields.includes(fieldsDragFieldRef.value)"
|
:is-field="template.fields.includes(fieldsDragFieldRef.value)"
|
||||||
|
:is-custom="!!customDragFieldRef.value"
|
||||||
:is-default="defaultFields.includes(toRaw(dragField))"
|
:is-default="defaultFields.includes(toRaw(dragField))"
|
||||||
:is-required="defaultRequiredFields.includes(toRaw(dragField))"
|
:is-required="defaultRequiredFields.includes(toRaw(dragField))"
|
||||||
/>
|
/>
|
||||||
@@ -362,7 +363,7 @@
|
|||||||
:is-drag="!!dragField"
|
:is-drag="!!dragField"
|
||||||
:input-mode="inputMode"
|
:input-mode="inputMode"
|
||||||
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
||||||
:allow-draw="!onlyDefinedFields || drawField"
|
:allow-draw="!onlyDefinedFields || drawField || drawCustomField"
|
||||||
:with-signature-id="withSignatureId"
|
:with-signature-id="withSignatureId"
|
||||||
:with-prefillable="withPrefillable"
|
:with-prefillable="withPrefillable"
|
||||||
:data-document-uuid="document.uuid"
|
:data-document-uuid="document.uuid"
|
||||||
@@ -371,14 +372,16 @@
|
|||||||
:with-field-placeholder="withFieldPlaceholder"
|
:with-field-placeholder="withFieldPlaceholder"
|
||||||
:draw-field="drawField"
|
:draw-field="drawField"
|
||||||
:draw-field-type="drawFieldType"
|
:draw-field-type="drawFieldType"
|
||||||
|
:draw-custom-field="drawCustomField"
|
||||||
:editable="editable"
|
:editable="editable"
|
||||||
:base-url="baseUrl"
|
:base-url="baseUrl"
|
||||||
:with-fields-detection="withFieldsDetection"
|
:with-fields-detection="withFieldsDetection"
|
||||||
@draw="[onDraw($event), withSelectedFieldType ? '' : drawFieldType = '', showDrawField = false]"
|
@draw="[onDraw($event), withSelectedFieldType ? '' : drawFieldType = '', drawCustomField = null, showDrawField = false]"
|
||||||
@drop-field="onDropfield"
|
@drop-field="onDropfield"
|
||||||
@remove-area="removeArea"
|
@remove-area="removeArea"
|
||||||
@paste-field="pasteField"
|
@paste-field="pasteField"
|
||||||
@copy-field="copyField"
|
@copy-field="copyField"
|
||||||
|
@add-custom-field="addCustomField"
|
||||||
@copy-selected-areas="copySelectedAreas"
|
@copy-selected-areas="copySelectedAreas"
|
||||||
@delete-selected-areas="deleteSelectedAreas"
|
@delete-selected-areas="deleteSelectedAreas"
|
||||||
@align-selected-areas="alignSelectedAreas"
|
@align-selected-areas="alignSelectedAreas"
|
||||||
@@ -436,15 +439,15 @@
|
|||||||
v-if="withFieldsList && !isMobile"
|
v-if="withFieldsList && !isMobile"
|
||||||
id="fields_list_container"
|
id="fields_list_container"
|
||||||
class="relative w-80 flex-none mt-1 pr-4 pl-0.5 hidden md:block fields-list-container"
|
class="relative w-80 flex-none mt-1 pr-4 pl-0.5 hidden md:block fields-list-container"
|
||||||
:class="drawField ? 'overflow-hidden' : 'overflow-y-auto overflow-x-hidden'"
|
:class="drawField || drawCustomField ? 'overflow-hidden' : 'overflow-y-auto overflow-x-hidden'"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="showDrawField || drawField"
|
v-if="showDrawField || drawField || drawCustomField"
|
||||||
class="sticky inset-0 h-full z-20"
|
class="sticky inset-0 h-full z-20"
|
||||||
:style="{ backgroundColor }"
|
:style="{ backgroundColor }"
|
||||||
>
|
>
|
||||||
<div class="bg-base-200 rounded-lg p-5 text-center space-y-4 draw-field-container">
|
<div class="bg-base-200 rounded-lg p-5 text-center space-y-4 draw-field-container">
|
||||||
<p v-if="(drawField?.type || drawFieldType) === 'strikethrough'">
|
<p v-if="(drawField?.type || drawFieldType || drawCustomField?.type) === 'strikethrough'">
|
||||||
{{ t('draw_strikethrough_the_document') }}
|
{{ t('draw_strikethrough_the_document') }}
|
||||||
</p>
|
</p>
|
||||||
<p v-else>
|
<p v-else>
|
||||||
@@ -458,10 +461,10 @@
|
|||||||
{{ t('cancel') }}
|
{{ t('cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
v-if="!drawField && !drawOption && !['stamp', 'signature', 'initials', 'heading', 'strikethrough'].includes(drawField?.type || drawFieldType)"
|
v-if="!drawField && !drawOption && !['stamp', 'signature', 'initials', 'heading', 'strikethrough'].includes(drawField?.type || drawFieldType || drawCustomField?.type)"
|
||||||
href="#"
|
href="#"
|
||||||
class="link block mt-3 text-sm"
|
class="link block mt-3 text-sm"
|
||||||
@click.prevent="[addField(drawFieldType), drawField = null, drawOption = null, withSelectedFieldType ? '' : drawFieldType = '', showDrawField = false]"
|
@click.prevent="drawCustomField ? addCustomFieldWithoutDraw() : [addField(drawFieldType), drawField = null, drawOption = null, withSelectedFieldType ? '' : drawFieldType = '', showDrawField = false]"
|
||||||
>
|
>
|
||||||
{{ t('or_add_field_without_drawing') }}
|
{{ t('or_add_field_without_drawing') }}
|
||||||
</a>
|
</a>
|
||||||
@@ -477,6 +480,8 @@
|
|||||||
:with-help="withHelp"
|
:with-help="withHelp"
|
||||||
:default-submitters="defaultSubmitters"
|
:default-submitters="defaultSubmitters"
|
||||||
:draw-field-type="drawFieldType"
|
:draw-field-type="drawFieldType"
|
||||||
|
:custom-fields="customFields"
|
||||||
|
:with-custom-fields="withCustomFields"
|
||||||
:with-fields-search="withFieldsSearch"
|
:with-fields-search="withFieldsSearch"
|
||||||
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
||||||
:template="template"
|
:template="template"
|
||||||
@@ -493,6 +498,7 @@
|
|||||||
@set-draw="[drawField = $event.field, drawOption = $event.option]"
|
@set-draw="[drawField = $event.field, drawOption = $event.option]"
|
||||||
@select-submitter="selectedSubmitter = $event"
|
@select-submitter="selectedSubmitter = $event"
|
||||||
@set-draw-type="[drawFieldType = $event, showDrawField = true]"
|
@set-draw-type="[drawFieldType = $event, showDrawField = true]"
|
||||||
|
@set-draw-custom-field="[drawCustomField = $event, showDrawField = true]"
|
||||||
@set-drag="dragField = $event"
|
@set-drag="dragField = $event"
|
||||||
@set-drag-placeholder="$refs.dragPlaceholder.dragPlaceholder = $event"
|
@set-drag-placeholder="$refs.dragPlaceholder.dragPlaceholder = $event"
|
||||||
@change-submitter="selectedSubmitter = $event"
|
@change-submitter="selectedSubmitter = $event"
|
||||||
@@ -632,10 +638,12 @@ export default {
|
|||||||
isPaymentConnected: this.isPaymentConnected,
|
isPaymentConnected: this.isPaymentConnected,
|
||||||
withFormula: this.withFormula,
|
withFormula: this.withFormula,
|
||||||
withConditions: this.withConditions,
|
withConditions: this.withConditions,
|
||||||
|
withCustomFields: this.withCustomFields,
|
||||||
isInlineSize: this.isInlineSize,
|
isInlineSize: this.isInlineSize,
|
||||||
defaultDrawFieldType: this.defaultDrawFieldType,
|
defaultDrawFieldType: this.defaultDrawFieldType,
|
||||||
selectedAreasRef: computed(() => this.selectedAreasRef),
|
selectedAreasRef: computed(() => this.selectedAreasRef),
|
||||||
fieldsDragFieldRef: computed(() => this.fieldsDragFieldRef),
|
fieldsDragFieldRef: computed(() => this.fieldsDragFieldRef),
|
||||||
|
customDragFieldRef: computed(() => this.customDragFieldRef),
|
||||||
isSelectModeRef: computed(() => this.isSelectModeRef),
|
isSelectModeRef: computed(() => this.isSelectModeRef),
|
||||||
isCmdKeyRef: computed(() => this.isCmdKeyRef)
|
isCmdKeyRef: computed(() => this.isCmdKeyRef)
|
||||||
}
|
}
|
||||||
@@ -705,6 +713,16 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
withCustomFields: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
customFields: {
|
||||||
|
type: Array,
|
||||||
|
required: false,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
withAddPageButton: {
|
withAddPageButton: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -902,6 +920,7 @@ export default {
|
|||||||
pendingFieldAttachmentUuids: [],
|
pendingFieldAttachmentUuids: [],
|
||||||
drawField: null,
|
drawField: null,
|
||||||
drawFieldType: null,
|
drawFieldType: null,
|
||||||
|
drawCustomField: null,
|
||||||
drawOption: null,
|
drawOption: null,
|
||||||
dragField: null,
|
dragField: null,
|
||||||
isDragFile: false
|
isDragFile: false
|
||||||
@@ -912,6 +931,7 @@ export default {
|
|||||||
isSelectModeRef: () => ref(false),
|
isSelectModeRef: () => ref(false),
|
||||||
isCmdKeyRef: () => ref(false),
|
isCmdKeyRef: () => ref(false),
|
||||||
fieldsDragFieldRef: () => ref(),
|
fieldsDragFieldRef: () => ref(),
|
||||||
|
customDragFieldRef: () => ref(),
|
||||||
selectedAreasRef: () => ref([]),
|
selectedAreasRef: () => ref([]),
|
||||||
language () {
|
language () {
|
||||||
return this.locale.split('-')[0].toLowerCase()
|
return this.locale.split('-')[0].toLowerCase()
|
||||||
@@ -1062,6 +1082,30 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toRaw,
|
toRaw,
|
||||||
|
addCustomField (field) {
|
||||||
|
return this.$refs.fields.addCustomField(field)
|
||||||
|
},
|
||||||
|
addCustomFieldWithoutDraw () {
|
||||||
|
const customField = this.drawCustomField
|
||||||
|
|
||||||
|
const field = JSON.parse(JSON.stringify(customField))
|
||||||
|
|
||||||
|
field.uuid = v4()
|
||||||
|
field.submitter_uuid = this.selectedSubmitter.uuid
|
||||||
|
field.areas = []
|
||||||
|
|
||||||
|
if (field.options?.length) {
|
||||||
|
field.options = field.options.map(opt => ({ ...opt, uuid: v4() }))
|
||||||
|
}
|
||||||
|
|
||||||
|
delete field.conditions
|
||||||
|
|
||||||
|
this.insertField(field)
|
||||||
|
this.save()
|
||||||
|
|
||||||
|
this.drawCustomField = null
|
||||||
|
this.showDrawField = false
|
||||||
|
},
|
||||||
toggleSelectMode () {
|
toggleSelectMode () {
|
||||||
this.isSelectModeRef.value = !this.isSelectModeRef.value
|
this.isSelectModeRef.value = !this.isSelectModeRef.value
|
||||||
|
|
||||||
@@ -1514,6 +1558,7 @@ export default {
|
|||||||
clearDrawField () {
|
clearDrawField () {
|
||||||
this.drawField = null
|
this.drawField = null
|
||||||
this.drawOption = null
|
this.drawOption = null
|
||||||
|
this.drawCustomField = null
|
||||||
this.showDrawField = false
|
this.showDrawField = false
|
||||||
|
|
||||||
if (!this.withSelectedFieldType) {
|
if (!this.withSelectedFieldType) {
|
||||||
@@ -1951,6 +1996,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDraw ({ area, isTooSmall }) {
|
onDraw ({ area, isTooSmall }) {
|
||||||
|
if (this.drawCustomField) {
|
||||||
|
return this.onDrawCustomField(area)
|
||||||
|
}
|
||||||
|
|
||||||
if (this.drawField) {
|
if (this.drawField) {
|
||||||
if (this.drawOption) {
|
if (this.drawOption) {
|
||||||
const areaWithoutOption = this.drawField.areas?.find((a) => !a.option_uuid)
|
const areaWithoutOption = this.drawField.areas?.find((a) => !a.option_uuid)
|
||||||
@@ -2061,6 +2110,10 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.customDragFieldRef.value) {
|
||||||
|
return this.dropCustomField(area)
|
||||||
|
}
|
||||||
|
|
||||||
const field = this.fieldsDragFieldRef.value || {
|
const field = this.fieldsDragFieldRef.value || {
|
||||||
name: '',
|
name: '',
|
||||||
uuid: v4(),
|
uuid: v4(),
|
||||||
@@ -2153,6 +2206,126 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
dropCustomField (area) {
|
||||||
|
const customField = this.customDragFieldRef.value
|
||||||
|
const customAreas = customField.areas || []
|
||||||
|
|
||||||
|
const field = JSON.parse(JSON.stringify(customField))
|
||||||
|
|
||||||
|
field.uuid = v4()
|
||||||
|
field.submitter_uuid = this.selectedSubmitter.uuid
|
||||||
|
field.areas = []
|
||||||
|
|
||||||
|
if (field.options?.length) {
|
||||||
|
field.options = field.options.map(opt => ({ ...opt, uuid: v4() }))
|
||||||
|
}
|
||||||
|
|
||||||
|
delete field.conditions
|
||||||
|
|
||||||
|
const dropX = (area.x - 6) / area.maskW
|
||||||
|
const dropY = area.y / area.maskH
|
||||||
|
|
||||||
|
if (customAreas.length > 0) {
|
||||||
|
const refArea = customAreas[0]
|
||||||
|
|
||||||
|
customAreas.forEach((customArea) => {
|
||||||
|
const fieldArea = {
|
||||||
|
x: dropX + (customArea.x - refArea.x),
|
||||||
|
y: dropY + (customArea.y - refArea.y) - (customArea.h / 2),
|
||||||
|
w: customArea.w,
|
||||||
|
h: customArea.h,
|
||||||
|
page: area.page,
|
||||||
|
attachment_uuid: area.attachment_uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customArea.cell_w) {
|
||||||
|
fieldArea.cell_w = customArea.cell_w
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customArea.option_uuid && field.options?.length) {
|
||||||
|
const optionIndex = customField.options.findIndex(o => o.uuid === customArea.option_uuid)
|
||||||
|
if (optionIndex !== -1) {
|
||||||
|
fieldArea.option_uuid = field.options[optionIndex].uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
field.areas.push(fieldArea)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const fieldArea = {
|
||||||
|
x: dropX,
|
||||||
|
y: dropY,
|
||||||
|
page: area.page,
|
||||||
|
attachment_uuid: area.attachment_uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
this.assignDropAreaSize(fieldArea, field, area)
|
||||||
|
|
||||||
|
field.areas.push(fieldArea)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedAreasRef.value = [field.areas[0]]
|
||||||
|
|
||||||
|
this.insertField(field)
|
||||||
|
this.save()
|
||||||
|
|
||||||
|
document.activeElement?.blur()
|
||||||
|
},
|
||||||
|
onDrawCustomField (area) {
|
||||||
|
const customField = this.drawCustomField
|
||||||
|
const customAreas = customField.areas || []
|
||||||
|
|
||||||
|
const field = JSON.parse(JSON.stringify(customField))
|
||||||
|
|
||||||
|
field.uuid = v4()
|
||||||
|
field.submitter_uuid = this.selectedSubmitter.uuid
|
||||||
|
field.areas = []
|
||||||
|
|
||||||
|
if (field.options?.length) {
|
||||||
|
field.options = field.options.map(opt => ({ ...opt, uuid: v4() }))
|
||||||
|
}
|
||||||
|
|
||||||
|
delete field.conditions
|
||||||
|
|
||||||
|
const isClick = area.w === 0 || area.h === 0
|
||||||
|
|
||||||
|
const firstArea = {
|
||||||
|
x: area.x,
|
||||||
|
y: area.y,
|
||||||
|
w: area.w || customAreas[0]?.w,
|
||||||
|
h: area.h || customAreas[0]?.h,
|
||||||
|
page: area.page,
|
||||||
|
attachment_uuid: area.attachment_uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstArea.w || !firstArea.h) {
|
||||||
|
if (customAreas[0]) {
|
||||||
|
firstArea.w = customAreas[0].w
|
||||||
|
firstArea.h = customAreas[0].h
|
||||||
|
} else {
|
||||||
|
this.setDefaultAreaSize(firstArea, field.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isClick) {
|
||||||
|
firstArea.x -= firstArea.w / 2
|
||||||
|
firstArea.y -= firstArea.h / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.options?.length) {
|
||||||
|
firstArea.option_uuid = field.options[0].uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
field.areas.push(firstArea)
|
||||||
|
|
||||||
|
this.selectedAreasRef.value = [field.areas[0]]
|
||||||
|
|
||||||
|
this.insertField(field)
|
||||||
|
this.save()
|
||||||
|
|
||||||
|
this.drawCustomField = null
|
||||||
|
this.showDrawField = false
|
||||||
|
},
|
||||||
assignDropAreaSize (fieldArea, field, area) {
|
assignDropAreaSize (fieldArea, field, area) {
|
||||||
const fieldType = field.type || 'text'
|
const fieldType = field.type || 'text'
|
||||||
|
|
||||||
|
|||||||
@@ -6,18 +6,24 @@
|
|||||||
<span
|
<span
|
||||||
ref="contenteditable"
|
ref="contenteditable"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
:contenteditable="editable"
|
:contenteditable="editable && (!editableOnButton || isEditable)"
|
||||||
style="min-width: 2px"
|
:data-placeholder="placeholder"
|
||||||
:class="[iconInline ? 'inline' : 'block', hideIcon ? 'focus:block' : '']"
|
:data-empty="isEmpty"
|
||||||
class="peer outline-none"
|
:style="{ minWidth }"
|
||||||
|
:class="[iconInline ? (isEmpty ? 'inline-block' : 'inline') : 'block', hideIcon ? 'focus:block' : '']"
|
||||||
|
class="peer relative inline-block outline-none before:pointer-events-none before:absolute before:left-0 before:top-0 before:select-none before:whitespace-pre before:text-neutral-400 before:content-[attr(data-placeholder)] before:opacity-0 data-[empty=true]:before:opacity-100"
|
||||||
@paste.prevent="onPaste"
|
@paste.prevent="onPaste"
|
||||||
@keydown.enter.prevent="blurContenteditable"
|
@keydown.enter.prevent="blurContenteditable"
|
||||||
|
@input="updateInputValue"
|
||||||
|
@cut="updateInputValue"
|
||||||
@focus="$emit('focus', $event)"
|
@focus="$emit('focus', $event)"
|
||||||
@blur="onBlur"
|
@blur="onBlur"
|
||||||
|
@click="editable && (!editableOnButton || isEditable) ? '' : $emit('click-contenteditable')"
|
||||||
>
|
>
|
||||||
{{ value }}
|
{{ value }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
|
v-if="withButton"
|
||||||
class="relative inline"
|
class="relative inline"
|
||||||
:class="{ 'peer-focus:hidden': hideIcon, 'peer-focus:invisible': !hideIcon }"
|
:class="{ 'peer-focus:hidden': hideIcon, 'peer-focus:invisible': !hideIcon }"
|
||||||
>
|
>
|
||||||
@@ -28,7 +34,7 @@
|
|||||||
:class="{ invisible: !editable, 'absolute top-1/2 -translate-y-1/2': !iconInline || floatIcon, 'inline align-bottom': iconInline, 'left-0': floatIcon }"
|
:class="{ invisible: !editable, 'absolute top-1/2 -translate-y-1/2': !iconInline || floatIcon, 'inline align-bottom': iconInline, 'left-0': floatIcon }"
|
||||||
:width="iconWidth + 4"
|
:width="iconWidth + 4"
|
||||||
:stroke-width="iconStrokeWidth"
|
:stroke-width="iconStrokeWidth"
|
||||||
@click="[focusContenteditable(), selectOnEditClick && selectContent()]"
|
@click="clickEdit"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,6 +55,16 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
withButton: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
iconInline: {
|
iconInline: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -74,6 +90,16 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
editableOnButton: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
minWidth: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: '2px'
|
||||||
|
},
|
||||||
editable: {
|
editable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -85,21 +111,34 @@ export default {
|
|||||||
default: 2
|
default: 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['update:model-value', 'focus', 'blur'],
|
emits: ['update:model-value', 'focus', 'blur', 'click-contenteditable'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
isEditable: false,
|
||||||
|
inputValue: '',
|
||||||
value: ''
|
value: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
isEmpty () {
|
||||||
|
return !this.inputValue.replace(/\u200B/g, '').replace(/\u00A0/g, ' ').trim()
|
||||||
|
}
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
modelValue: {
|
modelValue: {
|
||||||
handler (value) {
|
handler (value) {
|
||||||
this.value = value
|
this.value = value || ''
|
||||||
},
|
},
|
||||||
immediate: true
|
immediate: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted () {
|
||||||
|
this.updateInputValue()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
updateInputValue () {
|
||||||
|
this.inputValue = this.$refs.contenteditable?.textContent || ''
|
||||||
|
},
|
||||||
onPaste (e) {
|
onPaste (e) {
|
||||||
const text = (e.clipboardData || window.clipboardData).getData('text/plain')
|
const text = (e.clipboardData || window.clipboardData).getData('text/plain')
|
||||||
|
|
||||||
@@ -110,6 +149,20 @@ export default {
|
|||||||
selection.getRangeAt(0).insertNode(document.createTextNode(text))
|
selection.getRangeAt(0).insertNode(document.createTextNode(text))
|
||||||
selection.collapseToEnd()
|
selection.collapseToEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateInputValue()
|
||||||
|
},
|
||||||
|
clickEdit (e) {
|
||||||
|
this.focusContenteditable()
|
||||||
|
|
||||||
|
if (this.selectOnEditClick) {
|
||||||
|
this.selectContent()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setText (text) {
|
||||||
|
this.$refs.contenteditable.innerText = text
|
||||||
|
|
||||||
|
this.updateInputValue()
|
||||||
},
|
},
|
||||||
selectContent () {
|
selectContent () {
|
||||||
const el = this.$refs.contenteditable
|
const el = this.$refs.contenteditable
|
||||||
@@ -129,10 +182,18 @@ export default {
|
|||||||
this.value = this.$refs.contenteditable.innerText.trim() || this.modelValue
|
this.value = this.$refs.contenteditable.innerText.trim() || this.modelValue
|
||||||
this.$emit('update:model-value', this.value)
|
this.$emit('update:model-value', this.value)
|
||||||
this.$emit('blur', e)
|
this.$emit('blur', e)
|
||||||
|
|
||||||
|
this.isEditable = false
|
||||||
}, 1)
|
}, 1)
|
||||||
},
|
},
|
||||||
focusContenteditable () {
|
focusContenteditable () {
|
||||||
|
this.isEditable = true
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
this.$refs.contenteditable.focus()
|
this.$refs.contenteditable.focus()
|
||||||
|
|
||||||
|
this.updateInputValue()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
blurContenteditable () {
|
blurContenteditable () {
|
||||||
this.$refs.contenteditable.blur()
|
this.$refs.contenteditable.blur()
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="list-field group"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="border border-dashed border-base-300 hover:border-base-content/20 rounded relative group fields-list-item transition-colors"
|
||||||
|
:style="{ backgroundColor: backgroundColor }"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between relative group/contenteditable-container">
|
||||||
|
<div
|
||||||
|
v-if="!isNew"
|
||||||
|
class="absolute top-0 bottom-0 right-0 left-0 cursor-pointer"
|
||||||
|
@click="$emit('click', field)"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="absolute top-0 bottom-0 left-0 flex items-center transition-all cursor-grab group-hover:bg-base-200/50"
|
||||||
|
@click="$emit('click', field)"
|
||||||
|
>
|
||||||
|
<IconDrag style="margin-left: 1px" />
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center p-1 pl-6 space-x-1">
|
||||||
|
<FieldType
|
||||||
|
v-model="field.type"
|
||||||
|
:editable="false"
|
||||||
|
:button-width="20"
|
||||||
|
@click="$emit('click', field)"
|
||||||
|
/>
|
||||||
|
<Contenteditable
|
||||||
|
ref="name"
|
||||||
|
:model-value="field.name"
|
||||||
|
:placeholder="'Field Name'"
|
||||||
|
:icon-inline="true"
|
||||||
|
:icon-width="18"
|
||||||
|
:min-width="isNew ? '100px' : '2px'"
|
||||||
|
:icon-stroke-width="1.6"
|
||||||
|
:editable-on-button="!isNew"
|
||||||
|
:with-button="!isNew"
|
||||||
|
:class="{ 'cursor-pointer': !isNew }"
|
||||||
|
@click-contenteditable="$emit('click', field)"
|
||||||
|
@focus="onNameFocus"
|
||||||
|
@blur="onNameBlur"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-center space-x-1"
|
||||||
|
>
|
||||||
|
<PaymentSettings
|
||||||
|
v-if="field.type === 'payment' && !isNew"
|
||||||
|
:field="field"
|
||||||
|
:with-condition="false"
|
||||||
|
:with-force-open="false"
|
||||||
|
@click-description="isShowDescriptionModal = true"
|
||||||
|
@click-formula="isShowFormulaModal = true"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-else-if="!isNew"
|
||||||
|
class="dropdown dropdown-end field-settings-dropdown"
|
||||||
|
@mouseenter="renderDropdown = true"
|
||||||
|
@touchstart="renderDropdown = true"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
tabindex="0"
|
||||||
|
:title="t('settings')"
|
||||||
|
class="cursor-pointer text-transparent group-hover:text-base-content"
|
||||||
|
>
|
||||||
|
<IconSettings
|
||||||
|
:width="18"
|
||||||
|
:stroke-width="1.6"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<ul
|
||||||
|
v-if="renderDropdown"
|
||||||
|
tabindex="0"
|
||||||
|
class="mt-1.5 dropdown-content menu menu-xs p-2 shadow rounded-box w-52 z-10"
|
||||||
|
:style="{ backgroundColor: dropdownBgColor }"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart.prevent.stop
|
||||||
|
@click="closeDropdown"
|
||||||
|
>
|
||||||
|
<FieldSettings
|
||||||
|
:field="field"
|
||||||
|
:with-signature-id="withSignatureId"
|
||||||
|
:with-prefillable="withPrefillable"
|
||||||
|
:background-color="dropdownBgColor"
|
||||||
|
:with-areas="false"
|
||||||
|
:with-copy-to-all-pages="false"
|
||||||
|
:with-condition="false"
|
||||||
|
@click-formula="isShowFormulaModal = true"
|
||||||
|
@click-font="isShowFontModal = true"
|
||||||
|
@click-description="isShowDescriptionModal = true"
|
||||||
|
@save="$emit('save')"
|
||||||
|
/>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
v-if="isNew && !$refs.name"
|
||||||
|
class="relative text-base-content pr-1 field-save-button"
|
||||||
|
:title="t('save')"
|
||||||
|
@click="field.name ? $emit('save', field) : focusName()"
|
||||||
|
>
|
||||||
|
<IconCheck
|
||||||
|
:width="18"
|
||||||
|
:stroke-width="2"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="relative group-hover:text-base-content pr-1 field-remove-button"
|
||||||
|
:class="isNew ? 'text-base-content' : 'text-transparent group-hover:text-base-content'"
|
||||||
|
:title="t('remove')"
|
||||||
|
@click="onRemoveClick"
|
||||||
|
>
|
||||||
|
<IconTrashX
|
||||||
|
:width="18"
|
||||||
|
:stroke-width="1.6"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Teleport
|
||||||
|
v-if="isShowFormulaModal"
|
||||||
|
:to="modalContainerEl"
|
||||||
|
>
|
||||||
|
<FormulaModal
|
||||||
|
:field="field"
|
||||||
|
:default-field="defaultField"
|
||||||
|
:build-default-name="buildDefaultName"
|
||||||
|
@close="isShowFormulaModal = false"
|
||||||
|
/>
|
||||||
|
</Teleport>
|
||||||
|
<Teleport
|
||||||
|
v-if="isShowFontModal"
|
||||||
|
:to="modalContainerEl"
|
||||||
|
>
|
||||||
|
<FontModal
|
||||||
|
:field="field"
|
||||||
|
:default-field="defaultField"
|
||||||
|
:build-default-name="buildDefaultName"
|
||||||
|
@close="isShowFontModal = false"
|
||||||
|
/>
|
||||||
|
</Teleport>
|
||||||
|
<Teleport
|
||||||
|
v-if="isShowDescriptionModal"
|
||||||
|
:to="modalContainerEl"
|
||||||
|
>
|
||||||
|
<DescriptionModal
|
||||||
|
:field="field"
|
||||||
|
:default-field="defaultField"
|
||||||
|
:build-default-name="buildDefaultName"
|
||||||
|
@close="isShowDescriptionModal = false"
|
||||||
|
/>
|
||||||
|
</Teleport>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Contenteditable from './contenteditable'
|
||||||
|
import FieldType from './field_type'
|
||||||
|
import PaymentSettings from './payment_settings'
|
||||||
|
import FieldSettings from './field_settings'
|
||||||
|
import FormulaModal from './formula_modal'
|
||||||
|
import FontModal from './font_modal'
|
||||||
|
import DescriptionModal from './description_modal'
|
||||||
|
import { IconTrashX, IconSettings, IconCheck } from '@tabler/icons-vue'
|
||||||
|
import IconDrag from './icon_drag'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CustomField',
|
||||||
|
components: {
|
||||||
|
Contenteditable,
|
||||||
|
IconSettings,
|
||||||
|
IconCheck,
|
||||||
|
FieldSettings,
|
||||||
|
PaymentSettings,
|
||||||
|
IconDrag,
|
||||||
|
FormulaModal,
|
||||||
|
FontModal,
|
||||||
|
DescriptionModal,
|
||||||
|
IconTrashX,
|
||||||
|
FieldType
|
||||||
|
},
|
||||||
|
inject: ['backgroundColor', 't'],
|
||||||
|
props: {
|
||||||
|
field: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isNew: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
withSignatureId: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
withPrefillable: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['remove', 'save', 'click'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isShowFormulaModal: false,
|
||||||
|
isShowFontModal: false,
|
||||||
|
isShowDescriptionModal: false,
|
||||||
|
renderDropdown: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dropdownBgColor () {
|
||||||
|
return ['', null, 'transparent'].includes(this.backgroundColor) ? 'white' : this.backgroundColor
|
||||||
|
},
|
||||||
|
modalContainerEl () {
|
||||||
|
return this.$el.getRootNode().querySelector('#docuseal_modal_container')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.field.preferences ||= {}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if (this.isNew) {
|
||||||
|
this.focusName()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
buildDefaultName () {
|
||||||
|
return this.t('custom')
|
||||||
|
},
|
||||||
|
focusName () {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.name.clickEdit()
|
||||||
|
}, 1)
|
||||||
|
},
|
||||||
|
onNameFocus (e) {
|
||||||
|
if (!this.field.name) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.name.$refs.contenteditable.innerText = ' '
|
||||||
|
}, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeDropdown () {
|
||||||
|
this.$el.getRootNode().activeElement.blur()
|
||||||
|
},
|
||||||
|
onRemoveClick () {
|
||||||
|
if (this.isNew || window.confirm(this.t('are_you_sure_'))) {
|
||||||
|
this.$emit('remove', this.field)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onNameBlur (e) {
|
||||||
|
const text = this.$refs.name.$refs.contenteditable.innerText.trim()
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
this.field.name = text
|
||||||
|
} else {
|
||||||
|
this.$refs.name.setText(this.field.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.field.name) {
|
||||||
|
this.$emit('save')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
:default-submitters="defaultSubmitters"
|
:default-submitters="defaultSubmitters"
|
||||||
:draw-field="drawField"
|
:draw-field="drawField"
|
||||||
:draw-field-type="drawFieldType"
|
:draw-field-type="drawFieldType"
|
||||||
|
:draw-custom-field="drawCustomField"
|
||||||
:selected-submitter="selectedSubmitter"
|
:selected-submitter="selectedSubmitter"
|
||||||
:total-pages="sortedPreviewImages.length"
|
:total-pages="sortedPreviewImages.length"
|
||||||
:image="image"
|
:image="image"
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
@remove-area="$emit('remove-area', $event)"
|
@remove-area="$emit('remove-area', $event)"
|
||||||
@copy-field="$emit('copy-field', $event)"
|
@copy-field="$emit('copy-field', $event)"
|
||||||
@paste-field="$emit('paste-field', { ...$event, attachment_uuid: document.uuid })"
|
@paste-field="$emit('paste-field', { ...$event, attachment_uuid: document.uuid })"
|
||||||
|
@add-custom-field="$emit('add-custom-field', $event)"
|
||||||
@copy-selected-areas="$emit('copy-selected-areas')"
|
@copy-selected-areas="$emit('copy-selected-areas')"
|
||||||
@delete-selected-areas="$emit('delete-selected-areas')"
|
@delete-selected-areas="$emit('delete-selected-areas')"
|
||||||
@align-selected-areas="$emit('align-selected-areas', $event)"
|
@align-selected-areas="$emit('align-selected-areas', $event)"
|
||||||
@@ -115,6 +117,11 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
drawCustomField: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
baseUrl: {
|
baseUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -131,7 +138,7 @@ export default {
|
|||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['draw', 'drop-field', 'remove-area', 'paste-field', 'copy-field', 'copy-selected-areas', 'delete-selected-areas', 'align-selected-areas', 'autodetect-fields'],
|
emits: ['draw', 'drop-field', 'remove-area', 'paste-field', 'copy-field', 'copy-selected-areas', 'delete-selected-areas', 'align-selected-areas', 'autodetect-fields', 'add-custom-field'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
pageRefs: []
|
pageRefs: []
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
class="fixed z-20 pointer-events-none"
|
class="fixed z-20 pointer-events-none"
|
||||||
:editable="false"
|
:editable="false"
|
||||||
/>
|
/>
|
||||||
|
<CustomField
|
||||||
|
v-else-if="dragPlaceholder && isCustom && !isMask && field"
|
||||||
|
ref="dragPlaceholder"
|
||||||
|
:style="dragPlaceholderStyle"
|
||||||
|
:field="field"
|
||||||
|
class="fixed z-20 pointer-events-none opacity-90"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
v-else-if="dragPlaceholder && (isDefault || isRequired) && !isMask && field"
|
v-else-if="dragPlaceholder && (isDefault || isRequired) && !isMask && field"
|
||||||
ref="dragPlaceholder"
|
ref="dragPlaceholder"
|
||||||
@@ -57,6 +64,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Field from './field'
|
import Field from './field'
|
||||||
|
import CustomField from './custom_field'
|
||||||
import IconDrag from './icon_drag'
|
import IconDrag from './icon_drag'
|
||||||
import FieldType from './field_type'
|
import FieldType from './field_type'
|
||||||
|
|
||||||
@@ -64,6 +72,7 @@ export default {
|
|||||||
name: 'DragPlaceholder',
|
name: 'DragPlaceholder',
|
||||||
components: {
|
components: {
|
||||||
Field,
|
Field,
|
||||||
|
CustomField,
|
||||||
IconDrag
|
IconDrag
|
||||||
},
|
},
|
||||||
inject: ['t', 'backgroundColor'],
|
inject: ['t', 'backgroundColor'],
|
||||||
@@ -87,6 +96,11 @@ export default {
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
isCustom: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="list-field group mb-2"
|
class="list-field group"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="border border-base-300 rounded relative group fields-list-item"
|
class="border border-base-300 rounded relative group fields-list-item"
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
:button-width="20"
|
:button-width="20"
|
||||||
:menu-classes="'mt-1.5'"
|
:menu-classes="'mt-1.5'"
|
||||||
:menu-style="{ backgroundColor: dropdownBgColor }"
|
:menu-style="{ backgroundColor: dropdownBgColor }"
|
||||||
@update:model-value="[maybeUpdateOptions(), save()]"
|
@update:model-value="[maybeUpdateOptions(), $emit('save')]"
|
||||||
@click="scrollToFirstArea"
|
@click="scrollToFirstArea"
|
||||||
/>
|
/>
|
||||||
<Contenteditable
|
<Contenteditable
|
||||||
@@ -92,9 +92,12 @@
|
|||||||
<PaymentSettings
|
<PaymentSettings
|
||||||
v-if="field.type === 'payment'"
|
v-if="field.type === 'payment'"
|
||||||
:field="field"
|
:field="field"
|
||||||
|
:with-custom-fields="withCustomFields"
|
||||||
@click-condition="isShowConditionsModal = true"
|
@click-condition="isShowConditionsModal = true"
|
||||||
@click-description="isShowDescriptionModal = true"
|
@click-description="isShowDescriptionModal = true"
|
||||||
|
@add-custom-field="$emit('add-custom-field', $event)"
|
||||||
@click-formula="isShowFormulaModal = true"
|
@click-formula="isShowFormulaModal = true"
|
||||||
|
@save="$emit('save')"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
@@ -128,12 +131,15 @@
|
|||||||
:with-signature-id="withSignatureId"
|
:with-signature-id="withSignatureId"
|
||||||
:with-prefillable="withPrefillable"
|
:with-prefillable="withPrefillable"
|
||||||
:background-color="dropdownBgColor"
|
:background-color="dropdownBgColor"
|
||||||
|
:with-custom-fields="withCustomFields"
|
||||||
@click-formula="isShowFormulaModal = true"
|
@click-formula="isShowFormulaModal = true"
|
||||||
@click-font="isShowFontModal = true"
|
@click-font="isShowFontModal = true"
|
||||||
@click-description="isShowDescriptionModal = true"
|
@click-description="isShowDescriptionModal = true"
|
||||||
@click-condition="isShowConditionsModal = true"
|
@click-condition="isShowConditionsModal = true"
|
||||||
@set-draw="$emit('set-draw', $event)"
|
@set-draw="$emit('set-draw', $event)"
|
||||||
|
@add-custom-field="$emit('add-custom-field', $event)"
|
||||||
@remove-area="removeArea"
|
@remove-area="removeArea"
|
||||||
|
@save="$emit('save')"
|
||||||
@scroll-to="$emit('scroll-to', $event)"
|
@scroll-to="$emit('scroll-to', $event)"
|
||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -154,8 +160,10 @@
|
|||||||
v-if="field.options && withOptions && (isExpandOptions || field.options.length < 5)"
|
v-if="field.options && withOptions && (isExpandOptions || field.options.length < 5)"
|
||||||
ref="options"
|
ref="options"
|
||||||
class="border-t border-base-300 mx-2 pt-2 space-y-1.5"
|
class="border-t border-base-300 mx-2 pt-2 space-y-1.5"
|
||||||
|
draggable="true"
|
||||||
@dragover="onOptionDragover"
|
@dragover="onOptionDragover"
|
||||||
@drop="reorderOptions"
|
@drop="reorderOptions"
|
||||||
|
@dragstart.prevent.stop
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(option, index) in field.options"
|
v-for="(option, index) in field.options"
|
||||||
@@ -184,7 +192,8 @@
|
|||||||
required
|
required
|
||||||
:placeholder="`${t('option')} ${index + 1}`"
|
:placeholder="`${t('option')} ${index + 1}`"
|
||||||
@keydown.enter="option.value ? addOptionAt(index + 1) : null"
|
@keydown.enter="option.value ? addOptionAt(index + 1) : null"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
|
@paste="onOptionPaste($event, index)"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
:title="t('draw')"
|
:title="t('draw')"
|
||||||
@@ -208,7 +217,8 @@
|
|||||||
dir="auto"
|
dir="auto"
|
||||||
@keydown.enter="option.value ? addOptionAt(index + 1) : null"
|
@keydown.enter="option.value ? addOptionAt(index + 1) : null"
|
||||||
@focus="maybeFocusOnOptionArea(option)"
|
@focus="maybeFocusOnOptionArea(option)"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
|
@paste="onOptionPaste($event, index)"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
v-if="editable && !defaultField"
|
v-if="editable && !defaultField"
|
||||||
@@ -330,7 +340,7 @@ export default {
|
|||||||
IconMathFunction,
|
IconMathFunction,
|
||||||
FieldType
|
FieldType
|
||||||
},
|
},
|
||||||
inject: ['template', 'save', 'backgroundColor', 'selectedAreasRef', 't', 'locale'],
|
inject: ['template', 'backgroundColor', 'selectedAreasRef', 't', 'locale'],
|
||||||
props: {
|
props: {
|
||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -341,6 +351,11 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
withCustomFields: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
withPrefillable: {
|
withPrefillable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -362,12 +377,11 @@ export default {
|
|||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['set-draw', 'remove', 'scroll-to'],
|
emits: ['set-draw', 'remove', 'scroll-to', 'save', 'add-custom-field'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isExpandOptions: false,
|
isExpandOptions: false,
|
||||||
isNameFocus: false,
|
isNameFocus: false,
|
||||||
showPaymentModal: false,
|
|
||||||
isShowFormulaModal: false,
|
isShowFormulaModal: false,
|
||||||
isShowFontModal: false,
|
isShowFontModal: false,
|
||||||
isShowConditionsModal: false,
|
isShowConditionsModal: false,
|
||||||
@@ -416,7 +430,7 @@ export default {
|
|||||||
removeArea (area) {
|
removeArea (area) {
|
||||||
this.field.areas.splice(this.field.areas.indexOf(area), 1)
|
this.field.areas.splice(this.field.areas.indexOf(area), 1)
|
||||||
|
|
||||||
this.save()
|
this.$emit('save')
|
||||||
},
|
},
|
||||||
buildDefaultName (field, fields) {
|
buildDefaultName (field, fields) {
|
||||||
if (field.type === 'payment' && field.preferences?.price && !field.preferences?.formula) {
|
if (field.type === 'payment' && field.preferences?.price && !field.preferences?.formula) {
|
||||||
@@ -460,6 +474,35 @@ export default {
|
|||||||
closeDropdown () {
|
closeDropdown () {
|
||||||
this.$el.getRootNode().activeElement.blur()
|
this.$el.getRootNode().activeElement.blur()
|
||||||
},
|
},
|
||||||
|
onOptionPaste (e, index) {
|
||||||
|
const text = e.clipboardData.getData('text')
|
||||||
|
|
||||||
|
if (text.includes('\n')) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.isExpandOptions = true
|
||||||
|
|
||||||
|
const lines = text.split(/\r?\n/).map((l) => l.trim()).filter((l) => l)
|
||||||
|
|
||||||
|
if (lines.length > 0) {
|
||||||
|
const currentOption = this.field.options[index]
|
||||||
|
|
||||||
|
currentOption.value = (currentOption.value + lines[0]).trim()
|
||||||
|
|
||||||
|
const newOptions = lines.slice(1).map((line) => ({ value: line, uuid: v4() }))
|
||||||
|
|
||||||
|
this.field.options.splice(index + 1, 0, ...newOptions)
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const inputs = this.$refs.options.querySelectorAll('input')
|
||||||
|
|
||||||
|
inputs[index + newOptions.length]?.focus()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$emit('save')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
addOptionAt (index) {
|
addOptionAt (index) {
|
||||||
this.isExpandOptions = true
|
this.isExpandOptions = true
|
||||||
|
|
||||||
@@ -473,7 +516,7 @@ export default {
|
|||||||
inputs[insertAt]?.focus()
|
inputs[insertAt]?.focus()
|
||||||
})
|
})
|
||||||
|
|
||||||
this.save()
|
this.$emit('save')
|
||||||
},
|
},
|
||||||
removeOption (option) {
|
removeOption (option) {
|
||||||
this.field.options.splice(this.field.options.indexOf(option), 1)
|
this.field.options.splice(this.field.options.indexOf(option), 1)
|
||||||
@@ -484,7 +527,7 @@ export default {
|
|||||||
this.field.areas.splice(this.field.areas.findIndex((a) => a.option_uuid === option.uuid), 1)
|
this.field.areas.splice(this.field.areas.findIndex((a) => a.option_uuid === option.uuid), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save()
|
this.$emit('save')
|
||||||
},
|
},
|
||||||
maybeUpdateOptions () {
|
maybeUpdateOptions () {
|
||||||
delete this.field.default_value
|
delete this.field.default_value
|
||||||
@@ -526,7 +569,7 @@ export default {
|
|||||||
|
|
||||||
this.isNameFocus = false
|
this.isNameFocus = false
|
||||||
|
|
||||||
this.save()
|
this.$emit('save')
|
||||||
},
|
},
|
||||||
onOptionDragstart (event, option) {
|
onOptionDragstart (event, option) {
|
||||||
this.optionDragRef = option
|
this.optionDragRef = option
|
||||||
@@ -587,7 +630,7 @@ export default {
|
|||||||
if (newOrder.length === this.field.options.length) {
|
if (newOrder.length === this.field.options.length) {
|
||||||
this.field.options.splice(0, this.field.options.length, ...newOrder)
|
this.field.options.splice(0, this.field.options.length, ...newOrder)
|
||||||
|
|
||||||
this.save()
|
this.$emit('save')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.optionDragRef = null
|
this.optionDragRef = null
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<select
|
<select
|
||||||
:placeholder="t('method')"
|
:placeholder="t('method')"
|
||||||
class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0 bg-transparent"
|
class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0 bg-transparent"
|
||||||
@change="[field.preferences ||= {}, field.preferences.method = $event.target.value, save()]"
|
@change="[field.preferences ||= {}, field.preferences.method = $event.target.value, $emit('save')]"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
v-for="method in ['QeS', 'AeS']"
|
v-for="method in ['QeS', 'AeS']"
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
class="select select-bordered select-xs w-full max-w-xs h-7 !outline-0 font-normal bg-transparent"
|
class="select select-bordered select-xs w-full max-w-xs h-7 !outline-0 font-normal bg-transparent"
|
||||||
@change="[field.preferences ||= {}, field.preferences.align = $event.target.value, save()]"
|
@change="[field.preferences ||= {}, field.preferences.align = $event.target.value, $emit('save')]"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
v-for="value in ['left', 'right', field.type === 'cells' ? null : 'center'].filter(Boolean)"
|
v-for="value in ['left', 'right', field.type === 'cells' ? null : 'center'].filter(Boolean)"
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
:placeholder="t('default_value')"
|
:placeholder="t('default_value')"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
class="select select-bordered select-xs w-full max-w-xs h-7 !outline-0 font-normal bg-transparent"
|
class="select select-bordered select-xs w-full max-w-xs h-7 !outline-0 font-normal bg-transparent"
|
||||||
@change="[field.default_value = $event.target.value, !field.default_value && delete field.default_value, save()]"
|
@change="[field.default_value = $event.target.value, !field.default_value && delete field.default_value, $emit('save')]"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
value=""
|
value=""
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
dir="auto"
|
dir="auto"
|
||||||
:type="field.type"
|
:type="field.type"
|
||||||
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0 bg-transparent"
|
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0 bg-transparent"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
v-if="field.default_value"
|
v-if="field.default_value"
|
||||||
@@ -159,7 +159,7 @@
|
|||||||
:value="lengthValidation.min"
|
:value="lengthValidation.min"
|
||||||
class="input input-bordered w-full input-xs h-7 !outline-0 bg-transparent"
|
class="input input-bordered w-full input-xs h-7 !outline-0 bg-transparent"
|
||||||
@input="field.validation.pattern = `.{${$event.target.value || 0},${lengthValidation.max || ''}}`"
|
@input="field.validation.pattern = `.{${$event.target.value || 0},${lengthValidation.max || ''}}`"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
v-if="lengthValidation.min"
|
v-if="lengthValidation.min"
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
class="input input-bordered w-full input-xs h-7 !outline-0 bg-transparent"
|
class="input input-bordered w-full input-xs h-7 !outline-0 bg-transparent"
|
||||||
:value="lengthValidation.max"
|
:value="lengthValidation.max"
|
||||||
@input="field.validation.pattern = `.{${lengthValidation.min},${$event.target.value || ''}}`"
|
@input="field.validation.pattern = `.{${lengthValidation.min},${$event.target.value || ''}}`"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
v-if="lengthValidation.max"
|
v-if="lengthValidation.max"
|
||||||
@@ -203,7 +203,7 @@
|
|||||||
:value="field.validation?.min"
|
:value="field.validation?.min"
|
||||||
class="input input-bordered w-full input-xs h-7 !outline-0 bg-transparent"
|
class="input input-bordered w-full input-xs h-7 !outline-0 bg-transparent"
|
||||||
@input="[field.validation ||= {}, $event.target.value ? field.validation.min = $event.target.value : delete field.validation.min]"
|
@input="[field.validation ||= {}, $event.target.value ? field.validation.min = $event.target.value : delete field.validation.min]"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
v-if="field.validation?.min"
|
v-if="field.validation?.min"
|
||||||
@@ -222,7 +222,7 @@
|
|||||||
class="input input-bordered w-full input-xs h-7 !outline-0 bg-transparent"
|
class="input input-bordered w-full input-xs h-7 !outline-0 bg-transparent"
|
||||||
:value="field.validation?.max"
|
:value="field.validation?.max"
|
||||||
@input="[field.validation ||= {}, $event.target.value ? field.validation.max = $event.target.value : delete field.validation.max]"
|
@input="[field.validation ||= {}, $event.target.value ? field.validation.max = $event.target.value : delete field.validation.max]"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
v-if="field.validation?.max"
|
v-if="field.validation?.max"
|
||||||
@@ -242,7 +242,7 @@
|
|||||||
<select
|
<select
|
||||||
:placeholder="t('format')"
|
:placeholder="t('format')"
|
||||||
class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0 bg-transparent"
|
class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0 bg-transparent"
|
||||||
@change="[field.preferences ||= {}, field.preferences.format = $event.target.value, save()]"
|
@change="[field.preferences ||= {}, field.preferences.format = $event.target.value, $emit('save')]"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
v-for="format in numberFormats"
|
v-for="format in numberFormats"
|
||||||
@@ -272,7 +272,7 @@
|
|||||||
:placeholder="t('regexp_validation')"
|
:placeholder="t('regexp_validation')"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0 bg-transparent"
|
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0 bg-transparent"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
v-if="field.validation.pattern"
|
v-if="field.validation.pattern"
|
||||||
@@ -293,7 +293,7 @@
|
|||||||
:placeholder="t('error_message')"
|
:placeholder="t('error_message')"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0 bg-transparent"
|
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0 bg-transparent"
|
||||||
@blur="save"
|
@blur="$emit('save')"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
v-if="field.validation.message"
|
v-if="field.validation.message"
|
||||||
@@ -313,7 +313,7 @@
|
|||||||
v-model="field.preferences.format"
|
v-model="field.preferences.format"
|
||||||
:placeholder="t('format')"
|
:placeholder="t('format')"
|
||||||
class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0 bg-transparent"
|
class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0 bg-transparent"
|
||||||
@change="save"
|
@change="$emit('save')"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
v-for="format in dateFormats"
|
v-for="format in dateFormats"
|
||||||
@@ -339,7 +339,7 @@
|
|||||||
<select
|
<select
|
||||||
:placeholder="t('format')"
|
:placeholder="t('format')"
|
||||||
class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0 bg-transparent"
|
class="select select-bordered select-xs font-normal w-full max-w-xs !h-7 !outline-0 bg-transparent"
|
||||||
@change="[field.preferences.format = $event.target.value, save()]"
|
@change="[field.preferences.format = $event.target.value, $emit('save')]"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
value="any"
|
value="any"
|
||||||
@@ -374,7 +374,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
:disabled="!editable || (defaultField && [true, false].includes(defaultField.required))"
|
:disabled="!editable || (defaultField && [true, false].includes(defaultField.required))"
|
||||||
class="toggle toggle-xs"
|
class="toggle toggle-xs"
|
||||||
@change="[field.preferences ||= {}, field.preferences.with_signature_id = $event.target.checked, save()]"
|
@change="[field.preferences ||= {}, field.preferences.with_signature_id = $event.target.checked, $emit('save')]"
|
||||||
>
|
>
|
||||||
<span class="label-text">{{ t('signature_id') }}</span>
|
<span class="label-text">{{ t('signature_id') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -389,7 +389,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
:disabled="!editable || (defaultField && [true, false].includes(defaultField.required))"
|
:disabled="!editable || (defaultField && [true, false].includes(defaultField.required))"
|
||||||
class="toggle toggle-xs"
|
class="toggle toggle-xs"
|
||||||
@update:model-value="save"
|
@update:model-value="$emit('save')"
|
||||||
>
|
>
|
||||||
<span class="label-text">{{ t('required') }}</span>
|
<span class="label-text">{{ t('required') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -403,7 +403,7 @@
|
|||||||
:checked="field.preferences?.with_logo != false"
|
:checked="field.preferences?.with_logo != false"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="toggle toggle-xs"
|
class="toggle toggle-xs"
|
||||||
@change="[field.preferences ||= {}, field.preferences.with_logo = field.preferences.with_logo == false, save()]"
|
@change="[field.preferences ||= {}, field.preferences.with_logo = field.preferences.with_logo == false, $emit('save')]"
|
||||||
>
|
>
|
||||||
<span class="label-text">{{ t('with_logo') }}</span>
|
<span class="label-text">{{ t('with_logo') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -417,7 +417,7 @@
|
|||||||
v-model="field.default_value"
|
v-model="field.default_value"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="toggle toggle-xs"
|
class="toggle toggle-xs"
|
||||||
@update:model-value="[field.default_value = $event, field.readonly = $event, save()]"
|
@update:model-value="[field.default_value = $event, field.readonly = $event, $emit('save')]"
|
||||||
>
|
>
|
||||||
<span class="label-text">{{ t('checked') }}</span>
|
<span class="label-text">{{ t('checked') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -431,7 +431,7 @@
|
|||||||
v-model="field.readonly"
|
v-model="field.readonly"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="toggle toggle-xs"
|
class="toggle toggle-xs"
|
||||||
@update:model-value="[field.default_value = $event ? '{{date}}' : null, field.readonly = $event, save()]"
|
@update:model-value="[field.default_value = $event ? '{{date}}' : null, field.readonly = $event, $emit('save')]"
|
||||||
>
|
>
|
||||||
<span class="label-text">{{ t('set_signing_date') }}</span>
|
<span class="label-text">{{ t('set_signing_date') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -446,7 +446,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="toggle toggle-xs"
|
class="toggle toggle-xs"
|
||||||
:disabled="!editable || (defaultField && [true, false].includes(defaultField.readonly))"
|
:disabled="!editable || (defaultField && [true, false].includes(defaultField.readonly))"
|
||||||
@update:model-value="save"
|
@update:model-value="$emit('save')"
|
||||||
>
|
>
|
||||||
<span class="label-text">{{ t('read_only') }}</span>
|
<span class="label-text">{{ t('read_only') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -461,7 +461,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
:disabled="!editable || (defaultField && [true, false].includes(defaultField.prefillable))"
|
:disabled="!editable || (defaultField && [true, false].includes(defaultField.prefillable))"
|
||||||
class="toggle toggle-xs"
|
class="toggle toggle-xs"
|
||||||
@update:model-value="save"
|
@update:model-value="$emit('save')"
|
||||||
>
|
>
|
||||||
<span class="label-text">{{ t('prefillable') }}</span>
|
<span class="label-text">{{ t('prefillable') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -499,7 +499,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="field.type != 'stamp' && field.type != 'heading'"
|
v-if="withCondition && field.type != 'stamp' && field.type != 'heading'"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="label-text cursor-pointer text-center w-full flex items-center"
|
class="label-text cursor-pointer text-center w-full flex items-center"
|
||||||
@@ -526,7 +526,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<hr class="pb-0.5 mt-0.5">
|
<hr
|
||||||
|
v-if="withCopyToAllPages || withAreas || withCustomFields"
|
||||||
|
class="pb-0.5 mt-0.5"
|
||||||
|
>
|
||||||
<template v-if="withAreas">
|
<template v-if="withAreas">
|
||||||
<li
|
<li
|
||||||
v-for="(area, index) in sortedAreas"
|
v-for="(area, index) in sortedAreas"
|
||||||
@@ -564,7 +567,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
<li v-if="field.areas?.length === 1 && ['date', 'signature', 'initials', 'text', 'cells', 'stamp'].includes(field.type)">
|
<li v-if="withCopyToAllPages && field.areas?.length === 1 && ['date', 'signature', 'initials', 'text', 'cells', 'stamp'].includes(field.type)">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="text-sm py-1 px-2"
|
class="text-sm py-1 px-2"
|
||||||
@@ -577,10 +580,23 @@
|
|||||||
{{ t('copy_to_all_pages') }}
|
{{ t('copy_to_all_pages') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li v-if="withCustomFields">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="text-sm py-1 px-2"
|
||||||
|
@click.prevent="$emit('add-custom-field', field)"
|
||||||
|
>
|
||||||
|
<IconForms
|
||||||
|
:width="20"
|
||||||
|
:stroke-width="1.6"
|
||||||
|
/>
|
||||||
|
{{ t('save_as_custom_field') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { IconRouteAltLeft, IconTypography, IconShape, IconX, IconMathFunction, IconNewSection, IconInfoCircle, IconCopy } from '@tabler/icons-vue'
|
import { IconRouteAltLeft, IconTypography, IconShape, IconX, IconMathFunction, IconNewSection, IconInfoCircle, IconCopy, IconForms } from '@tabler/icons-vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FieldSettings',
|
name: 'FieldSettings',
|
||||||
@@ -589,17 +605,33 @@ export default {
|
|||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconMathFunction,
|
IconMathFunction,
|
||||||
IconRouteAltLeft,
|
IconRouteAltLeft,
|
||||||
|
IconForms,
|
||||||
IconCopy,
|
IconCopy,
|
||||||
IconNewSection,
|
IconNewSection,
|
||||||
IconTypography,
|
IconTypography,
|
||||||
IconX
|
IconX
|
||||||
},
|
},
|
||||||
inject: ['template', 'save', 't'],
|
inject: ['template', 't'],
|
||||||
props: {
|
props: {
|
||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
withCondition: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
withCustomFields: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
withCopyToAllPages: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
withSignatureId: {
|
withSignatureId: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -636,7 +668,7 @@ export default {
|
|||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['set-draw', 'scroll-to', 'click-formula', 'click-description', 'click-condition', 'click-font', 'remove-area'],
|
emits: ['set-draw', 'scroll-to', 'click-formula', 'click-description', 'click-condition', 'click-font', 'remove-area', 'save', 'add-custom-field'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
selectedValidation: ''
|
selectedValidation: ''
|
||||||
@@ -730,7 +762,7 @@ export default {
|
|||||||
delete this.field.validation
|
delete this.field.validation
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save()
|
this.$emit('save')
|
||||||
},
|
},
|
||||||
copyToAllPages (field) {
|
copyToAllPages (field) {
|
||||||
const areaString = JSON.stringify(field.areas[0])
|
const areaString = JSON.stringify(field.areas[0])
|
||||||
@@ -747,7 +779,7 @@ export default {
|
|||||||
|
|
||||||
this.$emit('scroll-to', this.field.areas[this.field.areas.length - 1])
|
this.$emit('scroll-to', this.field.areas[this.field.areas.length - 1])
|
||||||
|
|
||||||
this.save()
|
this.$emit('save')
|
||||||
},
|
},
|
||||||
formatNumber (number, format) {
|
formatNumber (number, format) {
|
||||||
if (format === 'comma') {
|
if (format === 'comma') {
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
ref="fields"
|
ref="fields"
|
||||||
class="fields mb-1 mt-2"
|
class="fields mt-2"
|
||||||
|
:class="{ 'mb-1': !withCustomFields || !customFields.length }"
|
||||||
@dragover.prevent="onFieldDragover"
|
@dragover.prevent="onFieldDragover"
|
||||||
@drop="fieldsDragFieldRef.value ? reorderFields() : null"
|
@drop="fieldsDragFieldRef.value ? reorderFields() : null"
|
||||||
>
|
>
|
||||||
@@ -30,7 +31,11 @@
|
|||||||
:with-prefillable="withPrefillable"
|
:with-prefillable="withPrefillable"
|
||||||
:default-field="defaultFieldsIndex[field.name]"
|
:default-field="defaultFieldsIndex[field.name]"
|
||||||
:draggable="editable"
|
:draggable="editable"
|
||||||
|
:with-custom-fields="withCustomFields"
|
||||||
|
class="mb-1.5"
|
||||||
|
@add-custom-field="addCustomField"
|
||||||
@dragstart="[fieldsDragFieldRef.value = field, removeDragOverlay($event), setDragPlaceholder($event)]"
|
@dragstart="[fieldsDragFieldRef.value = field, removeDragOverlay($event), setDragPlaceholder($event)]"
|
||||||
|
@save="save"
|
||||||
@dragend="[fieldsDragFieldRef.value = null, $emit('set-drag-placeholder', null)]"
|
@dragend="[fieldsDragFieldRef.value = null, $emit('set-drag-placeholder', null)]"
|
||||||
@remove="removeField"
|
@remove="removeField"
|
||||||
@scroll-to="$emit('scroll-to-area', $event)"
|
@scroll-to="$emit('scroll-to-area', $event)"
|
||||||
@@ -105,7 +110,92 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="editable && !onlyDefinedFields"
|
v-if="editable && withCustomFields && (customFields.length || newCustomField)"
|
||||||
|
class="tabs w-full mb-1.5"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="tab tab-bordered w-1/2 border-base-300"
|
||||||
|
:class="{ 'tab-active': !showCustomTab }"
|
||||||
|
:style="{ '--tab-border': showCustomTab ? '0px' : '0.5px' }"
|
||||||
|
@click="setFieldsTab('default')"
|
||||||
|
>{{ t('default') }}</a>
|
||||||
|
<a
|
||||||
|
class="tab tab-bordered w-1/2 border-base-300"
|
||||||
|
:class="{ 'tab-active': showCustomTab }"
|
||||||
|
:style="{ '--tab-border': showCustomTab ? '0.5px' : '0px' }"
|
||||||
|
@click="setFieldsTab('custom')"
|
||||||
|
>{{ t('custom') }}</a>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="showCustomTab && editable"
|
||||||
|
ref="customFields"
|
||||||
|
class="custom-fields"
|
||||||
|
@dragover.prevent="onCustomFieldDragover"
|
||||||
|
@drop="customDragFieldRef.value ? reorderCustomFields() : null"
|
||||||
|
>
|
||||||
|
<template v-if="isShowCustomFieldSearch">
|
||||||
|
<input
|
||||||
|
v-model="customFieldsSearch"
|
||||||
|
:placeholder="t('search_field')"
|
||||||
|
class="input input-ghost input-xs px-0 text-base mb-1 !outline-0 !rounded bg-transparent w-full"
|
||||||
|
>
|
||||||
|
<hr class="mb-2">
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
ref="customFieldsList"
|
||||||
|
class="overflow-auto relative"
|
||||||
|
:style="{
|
||||||
|
maxHeight: isShowCustomFieldSearch ? '320px' : '',
|
||||||
|
minHeight: '320px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="!filteredCustomFields.length && customFieldsSearch"
|
||||||
|
class="top-0 bottom-0 text-center absolute flex items-center justify-center w-full flex-col"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{{ t('field_not_found') }}
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="link"
|
||||||
|
@click.prevent="customFieldsSearch = ''"
|
||||||
|
>
|
||||||
|
{{ t('clear') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<CustomField
|
||||||
|
v-if="newCustomField"
|
||||||
|
:key="newCustomField.uuid"
|
||||||
|
ref="newCustomField"
|
||||||
|
:data-uuid="newCustomField.uuid"
|
||||||
|
:is-new="true"
|
||||||
|
:field="newCustomField"
|
||||||
|
:draggable="false"
|
||||||
|
class="mb-1.5"
|
||||||
|
@save="onNewCustomFieldSave"
|
||||||
|
@remove="newCustomField = null"
|
||||||
|
/>
|
||||||
|
<CustomField
|
||||||
|
v-for="field in filteredCustomFields"
|
||||||
|
:key="field.uuid"
|
||||||
|
:data-uuid="field.uuid"
|
||||||
|
:field="field"
|
||||||
|
:draggable="true"
|
||||||
|
class="mb-1.5"
|
||||||
|
:with-signature-id="withSignatureId"
|
||||||
|
:with-prefillable="withPrefillable"
|
||||||
|
@save="saveCustomFields"
|
||||||
|
@click="$emit('set-draw-custom-field', field)"
|
||||||
|
@dragstart="[customDragFieldRef.value = field, removeDragOverlay($event), setDragPlaceholder($event)]"
|
||||||
|
@dragend="[customDragFieldRef.value = null, $emit('set-drag-placeholder', null)]"
|
||||||
|
@remove="removeCustomField"
|
||||||
|
@set-draw="$emit('set-draw', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="editable && !onlyDefinedFields && (!showCustomTab || (!customFields.length && !newCustomField))"
|
||||||
id="field-types-grid"
|
id="field-types-grid"
|
||||||
class="grid grid-cols-3 gap-1 pb-2 fields-grid"
|
class="grid grid-cols-3 gap-1 pb-2 fields-grid"
|
||||||
>
|
>
|
||||||
@@ -266,15 +356,18 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Field from './field'
|
import Field from './field'
|
||||||
|
import CustomField from './custom_field'
|
||||||
import FieldType from './field_type'
|
import FieldType from './field_type'
|
||||||
import FieldSubmitter from './field_submitter'
|
import FieldSubmitter from './field_submitter'
|
||||||
import { IconLock, IconCirclePlus, IconInnerShadowTop, IconSparkles } from '@tabler/icons-vue'
|
import { IconLock, IconCirclePlus, IconInnerShadowTop, IconSparkles } from '@tabler/icons-vue'
|
||||||
import IconDrag from './icon_drag'
|
import IconDrag from './icon_drag'
|
||||||
|
import { v4 } from 'uuid'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TemplateFields',
|
name: 'TemplateFields',
|
||||||
components: {
|
components: {
|
||||||
Field,
|
Field,
|
||||||
|
CustomField,
|
||||||
FieldType,
|
FieldType,
|
||||||
IconCirclePlus,
|
IconCirclePlus,
|
||||||
IconSparkles,
|
IconSparkles,
|
||||||
@@ -283,12 +376,22 @@ export default {
|
|||||||
IconDrag,
|
IconDrag,
|
||||||
IconLock
|
IconLock
|
||||||
},
|
},
|
||||||
inject: ['save', 'backgroundColor', 'withPhone', 'withVerification', 'withKba', 'withPayment', 't', 'fieldsDragFieldRef', 'baseFetch', 'selectedAreasRef'],
|
inject: ['save', 'backgroundColor', 'withPhone', 'withVerification', 'withKba', 'withPayment', 't', 'fieldsDragFieldRef', 'customDragFieldRef', 'baseFetch', 'selectedAreasRef'],
|
||||||
props: {
|
props: {
|
||||||
fields: {
|
fields: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
customFields: {
|
||||||
|
type: Array,
|
||||||
|
required: false,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
withCustomFields: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
withFieldsSearch: {
|
withFieldsSearch: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -372,12 +475,15 @@ export default {
|
|||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['add-field', 'set-draw', 'set-draw-type', 'set-drag', 'drag-end', 'scroll-to-area', 'change-submitter', 'set-drag-placeholder', 'select-submitter'],
|
emits: ['add-field', 'set-draw', 'set-draw-type', 'set-draw-custom-field', 'set-drag', 'drag-end', 'scroll-to-area', 'change-submitter', 'set-drag-placeholder', 'select-submitter'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
fieldPagesLoaded: null,
|
fieldPagesLoaded: null,
|
||||||
analyzingProgress: 0,
|
analyzingProgress: 0,
|
||||||
defaultFieldsSearch: ''
|
newCustomField: null,
|
||||||
|
showCustomTab: false,
|
||||||
|
defaultFieldsSearch: '',
|
||||||
|
customFieldsSearch: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -430,6 +536,23 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
return this.submitterDefaultFields
|
return this.submitterDefaultFields
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
isShowCustomFieldSearch () {
|
||||||
|
return this.customFields.length > 8
|
||||||
|
},
|
||||||
|
filteredCustomFields () {
|
||||||
|
if (this.customFieldsSearch) {
|
||||||
|
return this.customFields.filter((f) => f.name.toLowerCase().includes(this.customFieldsSearch.toLowerCase()))
|
||||||
|
} else {
|
||||||
|
return this.customFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
try {
|
||||||
|
this.showCustomTab = localStorage.getItem('docuseal_builder_tab') === 'custom'
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -440,6 +563,61 @@ export default {
|
|||||||
|
|
||||||
this.$emit('set-drag', field)
|
this.$emit('set-drag', field)
|
||||||
},
|
},
|
||||||
|
onNewCustomFieldSave () {
|
||||||
|
if (this.newCustomField.name) {
|
||||||
|
this.customFields.unshift(this.newCustomField)
|
||||||
|
this.newCustomField = null
|
||||||
|
|
||||||
|
this.saveCustomFields()
|
||||||
|
} else {
|
||||||
|
this.newCustomField = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addCustomField (field) {
|
||||||
|
const customField = JSON.parse(JSON.stringify(field))
|
||||||
|
|
||||||
|
customField.uuid = v4()
|
||||||
|
|
||||||
|
delete customField.submitter_uuid
|
||||||
|
delete customField.prefillable
|
||||||
|
delete customField.conditions
|
||||||
|
|
||||||
|
customField.areas?.forEach((area) => {
|
||||||
|
delete area.attachment_uuid
|
||||||
|
delete area.page
|
||||||
|
})
|
||||||
|
|
||||||
|
if (customField.name) {
|
||||||
|
this.customFields.unshift(customField)
|
||||||
|
this.saveCustomFields()
|
||||||
|
} else {
|
||||||
|
this.newCustomField = customField
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setFieldsTab('custom')
|
||||||
|
},
|
||||||
|
setFieldsTab (type) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem('docuseal_builder_tab', type)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showCustomTab = type === 'custom'
|
||||||
|
},
|
||||||
|
saveCustomFields () {
|
||||||
|
return this.baseFetch('/account_custom_fields', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
value: this.customFields
|
||||||
|
}),
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
}).then(async (resp) => {
|
||||||
|
const fields = await resp.json()
|
||||||
|
|
||||||
|
this.customFields.splice(0, this.customFields.length, ...fields)
|
||||||
|
})
|
||||||
|
},
|
||||||
detectFields () {
|
detectFields () {
|
||||||
const fields = []
|
const fields = []
|
||||||
|
|
||||||
@@ -617,6 +795,47 @@ export default {
|
|||||||
if (save) {
|
if (save) {
|
||||||
this.save()
|
this.save()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
removeCustomField (field) {
|
||||||
|
this.customFields.splice(this.customFields.indexOf(field), 1)
|
||||||
|
|
||||||
|
if (!this.customFields.length) {
|
||||||
|
this.setFieldsTab('default')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveCustomFields()
|
||||||
|
},
|
||||||
|
onCustomFieldDragover (e) {
|
||||||
|
if (this.customDragFieldRef.value && this.customFields.includes(this.customDragFieldRef.value)) {
|
||||||
|
const container = this.$refs.customFieldsList
|
||||||
|
const targetField = e.target.closest('[data-uuid]')
|
||||||
|
const dragField = container.querySelector(`[data-uuid="${this.customDragFieldRef.value.uuid}"]`)
|
||||||
|
|
||||||
|
if (dragField && targetField && targetField !== dragField) {
|
||||||
|
const fields = Array.from(container.children)
|
||||||
|
const currentIndex = fields.indexOf(dragField)
|
||||||
|
const targetIndex = fields.indexOf(targetField)
|
||||||
|
|
||||||
|
if (currentIndex < targetIndex) {
|
||||||
|
targetField.after(dragField)
|
||||||
|
} else {
|
||||||
|
targetField.before(dragField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reorderCustomFields () {
|
||||||
|
if (!this.customFields.includes(this.customDragFieldRef.value)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const reorderedFields = Array.from(this.$refs.customFieldsList.children).map((el) => {
|
||||||
|
return this.customFields.find((f) => f.uuid === el.dataset.uuid)
|
||||||
|
}).filter(Boolean)
|
||||||
|
|
||||||
|
this.customFields.splice(0, this.customFields.length, ...reorderedFields)
|
||||||
|
|
||||||
|
this.saveCustomFields()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
const en = {
|
const en = {
|
||||||
|
default: 'Default',
|
||||||
|
save_as_custom_field: 'Save as Custom Field',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
analyzing_: 'Analyzing...',
|
analyzing_: 'Analyzing...',
|
||||||
download: 'Download',
|
download: 'Download',
|
||||||
downloading_: 'Downloading...',
|
downloading_: 'Downloading...',
|
||||||
view: 'View',
|
view: 'View',
|
||||||
autodetect_fields: 'Autodetect fields',
|
autodetect_fields: 'Autodetect Fields',
|
||||||
payment_link: 'Payment link',
|
payment_link: 'Payment link',
|
||||||
strikeout: 'Strikeout',
|
strikeout: 'Strikeout',
|
||||||
draw_strikethrough_the_document: 'Draw strikethrough the document',
|
draw_strikethrough_the_document: 'Draw strikethrough the document',
|
||||||
@@ -200,6 +202,8 @@ const en = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const es = {
|
const es = {
|
||||||
|
default: 'Predeterminado',
|
||||||
|
save_as_custom_field: 'Guardar como personalizado',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Autodetectar campos',
|
autodetect_fields: 'Autodetectar campos',
|
||||||
analyzing_: 'Analizando...',
|
analyzing_: 'Analizando...',
|
||||||
@@ -401,6 +405,8 @@ const es = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const it = {
|
const it = {
|
||||||
|
default: 'Predefinito',
|
||||||
|
save_as_custom_field: 'Salva come personalizzato',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Rileva campi',
|
autodetect_fields: 'Rileva campi',
|
||||||
analyzing_: 'Analisi...',
|
analyzing_: 'Analisi...',
|
||||||
@@ -602,6 +608,8 @@ const it = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pt = {
|
const pt = {
|
||||||
|
default: 'Padrão',
|
||||||
|
save_as_custom_field: 'Salvar como personalizado',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Detectar campos',
|
autodetect_fields: 'Detectar campos',
|
||||||
analyzing_: 'Analisando...',
|
analyzing_: 'Analisando...',
|
||||||
@@ -803,6 +811,8 @@ const pt = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fr = {
|
const fr = {
|
||||||
|
default: 'Par défaut',
|
||||||
|
save_as_custom_field: 'Enregistrer comme personnalisé',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Détecter les champs',
|
autodetect_fields: 'Détecter les champs',
|
||||||
analyzing_: 'Analyse...',
|
analyzing_: 'Analyse...',
|
||||||
@@ -1004,6 +1014,8 @@ const fr = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const de = {
|
const de = {
|
||||||
|
default: 'Standard',
|
||||||
|
save_as_custom_field: 'Als benutzerdefiniert speichern',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Felder erkennen',
|
autodetect_fields: 'Felder erkennen',
|
||||||
analyzing_: 'Analysiere...',
|
analyzing_: 'Analysiere...',
|
||||||
@@ -1205,6 +1217,8 @@ const de = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nl = {
|
const nl = {
|
||||||
|
default: 'Standaard',
|
||||||
|
save_as_custom_field: 'Opslaan als aangepast',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Velden detecteren',
|
autodetect_fields: 'Velden detecteren',
|
||||||
analyzing_: 'Analyseren...',
|
analyzing_: 'Analyseren...',
|
||||||
|
|||||||
@@ -52,15 +52,22 @@
|
|||||||
@stop-resize="resizeDirection = null"
|
@stop-resize="resizeDirection = null"
|
||||||
@remove="$emit('remove-area', item.area)"
|
@remove="$emit('remove-area', item.area)"
|
||||||
@scroll-to="$emit('scroll-to', $event)"
|
@scroll-to="$emit('scroll-to', $event)"
|
||||||
|
@add-custom-field="$emit('add-custom-field', $event)"
|
||||||
@contextmenu="openAreaContextMenu($event, item.area, item.field)"
|
@contextmenu="openAreaContextMenu($event, item.area, item.field)"
|
||||||
/>
|
/>
|
||||||
<FieldArea
|
<FieldArea
|
||||||
v-if="newArea"
|
v-for="(area, index) in newAreas"
|
||||||
|
:key="index"
|
||||||
:is-draw="true"
|
:is-draw="true"
|
||||||
:page-width="width"
|
:page-width="width"
|
||||||
:page-height="height"
|
:page-height="height"
|
||||||
:field="{ submitter_uuid: selectedSubmitter.uuid, type: drawField?.type || dragFieldPlaceholder?.type || defaultFieldType }"
|
:field="{ submitter_uuid: selectedSubmitter.uuid, type: newAreaFieldType }"
|
||||||
:area="newArea"
|
:area="area"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="newAreas.length > 1"
|
||||||
|
class="absolute outline-dashed outline-gray-400 pointer-events-none z-20"
|
||||||
|
:style="newAreasBoxStyle"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="selectionRect"
|
v-if="selectionRect"
|
||||||
@@ -93,7 +100,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="resizeDirection || isDrag || showMask || (drawField && isMobile) || fieldsDragFieldRef.value || selectionRect"
|
v-show="resizeDirection || isDrag || showMask || (drawField && isMobile) || fieldsDragFieldRef.value || customDragFieldRef?.value || selectionRect"
|
||||||
id="mask"
|
id="mask"
|
||||||
ref="mask"
|
ref="mask"
|
||||||
class="top-0 bottom-0 left-0 right-0 absolute"
|
class="top-0 bottom-0 left-0 right-0 absolute"
|
||||||
@@ -103,7 +110,7 @@
|
|||||||
@contextmenu="openContextMenu"
|
@contextmenu="openContextMenu"
|
||||||
@dragover.prevent="onDragover"
|
@dragover.prevent="onDragover"
|
||||||
@dragenter="onDragenter"
|
@dragenter="onDragenter"
|
||||||
@dragleave="newArea = null"
|
@dragleave="newAreas = []"
|
||||||
@drop="onDrop"
|
@drop="onDrop"
|
||||||
@pointerup="onPointerup"
|
@pointerup="onPointerup"
|
||||||
/>
|
/>
|
||||||
@@ -122,7 +129,7 @@ export default {
|
|||||||
ContextMenu,
|
ContextMenu,
|
||||||
SelectionBox
|
SelectionBox
|
||||||
},
|
},
|
||||||
inject: ['fieldTypes', 'defaultDrawFieldType', 'fieldsDragFieldRef', 'assignDropAreaSize', 'selectedAreasRef', 'template', 'isSelectModeRef'],
|
inject: ['fieldTypes', 'defaultDrawFieldType', 'fieldsDragFieldRef', 'customDragFieldRef', 'assignDropAreaSize', 'selectedAreasRef', 'template', 'isSelectModeRef'],
|
||||||
props: {
|
props: {
|
||||||
image: {
|
image: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -191,6 +198,11 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
drawCustomField: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
editable: {
|
editable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -216,13 +228,13 @@ export default {
|
|||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['draw', 'drop-field', 'remove-area', 'copy-field', 'paste-field', 'scroll-to', 'copy-selected-areas', 'delete-selected-areas', 'align-selected-areas', 'autodetect-fields'],
|
emits: ['draw', 'drop-field', 'remove-area', 'copy-field', 'paste-field', 'scroll-to', 'copy-selected-areas', 'delete-selected-areas', 'align-selected-areas', 'autodetect-fields', 'add-custom-field'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
areaRefs: [],
|
areaRefs: [],
|
||||||
showMask: false,
|
showMask: false,
|
||||||
resizeDirection: null,
|
resizeDirection: null,
|
||||||
newArea: null,
|
newAreas: [],
|
||||||
contextMenu: null,
|
contextMenu: null,
|
||||||
selectionRect: null,
|
selectionRect: null,
|
||||||
selectionContextMenu: null
|
selectionContextMenu: null
|
||||||
@@ -274,6 +286,14 @@ export default {
|
|||||||
return acc
|
return acc
|
||||||
}, {})
|
}, {})
|
||||||
},
|
},
|
||||||
|
newAreaFieldType () {
|
||||||
|
if (this.drawField?.type) return this.drawField.type
|
||||||
|
if (this.drawCustomField?.type) return this.drawCustomField.type
|
||||||
|
if (this.dragFieldPlaceholder?.type) return this.dragFieldPlaceholder.type
|
||||||
|
if (this.customDragFieldRef?.value?.type) return this.customDragFieldRef.value.type
|
||||||
|
|
||||||
|
return this.defaultFieldType
|
||||||
|
},
|
||||||
defaultFieldType () {
|
defaultFieldType () {
|
||||||
if (this.drawFieldType) {
|
if (this.drawFieldType) {
|
||||||
return this.drawFieldType
|
return this.drawFieldType
|
||||||
@@ -302,6 +322,21 @@ export default {
|
|||||||
height () {
|
height () {
|
||||||
return this.image.metadata.height
|
return this.image.metadata.height
|
||||||
},
|
},
|
||||||
|
newAreasBoxStyle () {
|
||||||
|
if (this.newAreas.length < 2) return {}
|
||||||
|
|
||||||
|
const minX = Math.min(...this.newAreas.map(a => a.x))
|
||||||
|
const minY = Math.min(...this.newAreas.map(a => a.y))
|
||||||
|
const maxX = Math.max(...this.newAreas.map(a => a.x + a.w))
|
||||||
|
const maxY = Math.max(...this.newAreas.map(a => a.y + a.h))
|
||||||
|
|
||||||
|
return {
|
||||||
|
left: minX * 100 + '%',
|
||||||
|
top: minY * 100 + '%',
|
||||||
|
width: (maxX - minX) * 100 + '%',
|
||||||
|
height: (maxY - minY) * 100 + '%'
|
||||||
|
}
|
||||||
|
},
|
||||||
selectionRectStyle () {
|
selectionRectStyle () {
|
||||||
if (!this.selectionRect) return {}
|
if (!this.selectionRect) return {}
|
||||||
|
|
||||||
@@ -331,7 +366,7 @@ export default {
|
|||||||
|
|
||||||
const rect = this.$refs.image.getBoundingClientRect()
|
const rect = this.$refs.image.getBoundingClientRect()
|
||||||
|
|
||||||
this.newArea = null
|
this.newAreas = []
|
||||||
this.showMask = false
|
this.showMask = false
|
||||||
|
|
||||||
this.contextMenu = {
|
this.contextMenu = {
|
||||||
@@ -351,7 +386,7 @@ export default {
|
|||||||
|
|
||||||
const rect = this.$refs.image.getBoundingClientRect()
|
const rect = this.$refs.image.getBoundingClientRect()
|
||||||
|
|
||||||
this.newArea = null
|
this.newAreas = []
|
||||||
this.showMask = false
|
this.showMask = false
|
||||||
|
|
||||||
this.contextMenu = {
|
this.contextMenu = {
|
||||||
@@ -390,7 +425,7 @@ export default {
|
|||||||
},
|
},
|
||||||
closeContextMenu () {
|
closeContextMenu () {
|
||||||
this.contextMenu = null
|
this.contextMenu = null
|
||||||
this.newArea = null
|
this.newAreas = []
|
||||||
this.showMask = false
|
this.showMask = false
|
||||||
},
|
},
|
||||||
handleCopy () {
|
handleCopy () {
|
||||||
@@ -410,7 +445,7 @@ export default {
|
|||||||
this.closeContextMenu()
|
this.closeContextMenu()
|
||||||
},
|
},
|
||||||
handlePaste () {
|
handlePaste () {
|
||||||
this.newArea = null
|
this.newAreas = []
|
||||||
this.showMask = false
|
this.showMask = false
|
||||||
|
|
||||||
this.$emit('paste-field', {
|
this.$emit('paste-field', {
|
||||||
@@ -435,22 +470,66 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDragenter (e) {
|
onDragenter (e) {
|
||||||
this.newArea = {}
|
const customField = this.customDragFieldRef?.value
|
||||||
|
const customAreas = customField?.areas || []
|
||||||
|
const dropX = (e.offsetX - 6) / this.$refs.mask.clientWidth
|
||||||
|
const dropY = e.offsetY / this.$refs.mask.clientHeight
|
||||||
|
|
||||||
this.assignDropAreaSize(this.newArea, this.dragFieldPlaceholder, {
|
if (customAreas.length > 1) {
|
||||||
|
const refArea = customAreas[0]
|
||||||
|
|
||||||
|
this.newAreas = customAreas.map((customArea) => ({
|
||||||
|
x: dropX + (customArea.x - refArea.x),
|
||||||
|
y: dropY + (customArea.y - refArea.y) - (customArea.h / 2),
|
||||||
|
w: customArea.w,
|
||||||
|
h: customArea.h
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
const newArea = {}
|
||||||
|
|
||||||
|
if (customAreas.length === 1) {
|
||||||
|
newArea.w = customAreas[0].w
|
||||||
|
newArea.h = customAreas[0].h
|
||||||
|
} else if (customField) {
|
||||||
|
this.assignDropAreaSize(newArea, customField, {
|
||||||
maskW: this.$refs.mask.clientWidth,
|
maskW: this.$refs.mask.clientWidth,
|
||||||
maskH: this.$refs.mask.clientHeight
|
maskH: this.$refs.mask.clientHeight
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
this.assignDropAreaSize(newArea, this.dragFieldPlaceholder, {
|
||||||
|
maskW: this.$refs.mask.clientWidth,
|
||||||
|
maskH: this.$refs.mask.clientHeight
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
this.newArea.x = (e.offsetX - 6) / this.$refs.mask.clientWidth
|
newArea.x = dropX
|
||||||
this.newArea.y = e.offsetY / this.$refs.mask.clientHeight - this.newArea.h / 2
|
newArea.y = dropY - newArea.h / 2
|
||||||
|
|
||||||
|
this.newAreas = [newArea]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onDragover (e) {
|
onDragover (e) {
|
||||||
this.newArea.x = (e.offsetX - 6) / this.$refs.mask.clientWidth
|
const customField = this.customDragFieldRef?.value
|
||||||
this.newArea.y = e.offsetY / this.$refs.mask.clientHeight - this.newArea.h / 2
|
const customAreas = customField?.areas || []
|
||||||
|
const dropX = (e.offsetX - 6) / this.$refs.mask.clientWidth
|
||||||
|
const dropY = e.offsetY / this.$refs.mask.clientHeight
|
||||||
|
|
||||||
|
if (customAreas.length > 1) {
|
||||||
|
const refArea = customAreas[0]
|
||||||
|
|
||||||
|
this.newAreas.forEach((newArea, index) => {
|
||||||
|
const customArea = customAreas[index]
|
||||||
|
|
||||||
|
newArea.x = dropX + (customArea.x - refArea.x)
|
||||||
|
newArea.y = dropY + (customArea.y - refArea.y) - (customArea.h / 2)
|
||||||
|
})
|
||||||
|
} else if (this.newAreas.length) {
|
||||||
|
this.newAreas[0].x = dropX
|
||||||
|
this.newAreas[0].y = dropY - this.newAreas[0].h / 2
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onDrop (e) {
|
onDrop (e) {
|
||||||
this.newArea = null
|
this.newAreas = []
|
||||||
|
|
||||||
this.$emit('drop-field', {
|
this.$emit('drop-field', {
|
||||||
x: e.offsetX,
|
x: e.offsetX,
|
||||||
@@ -479,7 +558,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isMobile && !this.drawField) {
|
if (this.isMobile && !this.drawField && !this.drawCustomField) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,14 +569,14 @@ export default {
|
|||||||
this.showMask = true
|
this.showMask = true
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.newArea = {
|
this.newAreas = [{
|
||||||
initialX: e.offsetX / this.$refs.mask.clientWidth,
|
initialX: e.offsetX / this.$refs.mask.clientWidth,
|
||||||
initialY: e.offsetY / this.$refs.mask.clientHeight,
|
initialY: e.offsetY / this.$refs.mask.clientHeight,
|
||||||
x: e.offsetX / this.$refs.mask.clientWidth,
|
x: e.offsetX / this.$refs.mask.clientWidth,
|
||||||
y: e.offsetY / this.$refs.mask.clientHeight,
|
y: e.offsetY / this.$refs.mask.clientHeight,
|
||||||
w: 0,
|
w: 0,
|
||||||
h: 0
|
h: 0
|
||||||
}
|
}]
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
startSelectionRect (e) {
|
startSelectionRect (e) {
|
||||||
@@ -563,28 +642,30 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.newArea) {
|
const drawArea = this.newAreas[0]
|
||||||
const dx = e.offsetX / this.$refs.mask.clientWidth - this.newArea.initialX
|
|
||||||
const dy = e.offsetY / this.$refs.mask.clientHeight - this.newArea.initialY
|
if (drawArea?.initialX !== undefined) {
|
||||||
|
const dx = e.offsetX / this.$refs.mask.clientWidth - drawArea.initialX
|
||||||
|
const dy = e.offsetY / this.$refs.mask.clientHeight - drawArea.initialY
|
||||||
|
|
||||||
if (dx > 0) {
|
if (dx > 0) {
|
||||||
this.newArea.x = this.newArea.initialX
|
drawArea.x = drawArea.initialX
|
||||||
} else {
|
} else {
|
||||||
this.newArea.x = e.offsetX / this.$refs.mask.clientWidth
|
drawArea.x = e.offsetX / this.$refs.mask.clientWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dy > 0) {
|
if (dy > 0) {
|
||||||
this.newArea.y = this.newArea.initialY
|
drawArea.y = drawArea.initialY
|
||||||
} else {
|
} else {
|
||||||
this.newArea.y = e.offsetY / this.$refs.mask.clientHeight
|
drawArea.y = e.offsetY / this.$refs.mask.clientHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((this.drawField?.type || this.drawFieldType) === 'cells') {
|
if ((this.drawField?.type || this.drawCustomField?.type || this.drawFieldType) === 'cells') {
|
||||||
this.newArea.cell_w = this.newArea.h * (this.$refs.mask.clientHeight / this.$refs.mask.clientWidth)
|
drawArea.cell_w = drawArea.h * (this.$refs.mask.clientHeight / this.$refs.mask.clientWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.newArea.w = Math.abs(dx)
|
drawArea.w = Math.abs(dx)
|
||||||
this.newArea.h = Math.abs(dy)
|
drawArea.h = Math.abs(dy)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPointerup (e) {
|
onPointerup (e) {
|
||||||
@@ -601,29 +682,33 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.selectionRect = null
|
this.selectionRect = null
|
||||||
} else if (this.newArea) {
|
} else {
|
||||||
|
const drawArea = this.newAreas[0]
|
||||||
|
|
||||||
|
if (drawArea?.initialX !== undefined) {
|
||||||
const area = {
|
const area = {
|
||||||
x: this.newArea.x,
|
x: drawArea.x,
|
||||||
y: this.newArea.y,
|
y: drawArea.y,
|
||||||
w: this.newArea.w,
|
w: drawArea.w,
|
||||||
h: this.newArea.h,
|
h: drawArea.h,
|
||||||
page: this.number
|
page: this.number
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('cell_w' in this.newArea) {
|
if ('cell_w' in drawArea) {
|
||||||
area.cell_w = this.newArea.cell_w
|
area.cell_w = drawArea.cell_w
|
||||||
}
|
}
|
||||||
|
|
||||||
const dx = Math.abs(e.offsetX - this.$refs.mask.clientWidth * this.newArea.initialX)
|
const dx = Math.abs(e.offsetX - this.$refs.mask.clientWidth * drawArea.initialX)
|
||||||
const dy = Math.abs(e.offsetY - this.$refs.mask.clientHeight * this.newArea.initialY)
|
const dy = Math.abs(e.offsetY - this.$refs.mask.clientHeight * drawArea.initialY)
|
||||||
|
|
||||||
const isTooSmall = dx < 8 && dy < 8
|
const isTooSmall = dx < 8 && dy < 8
|
||||||
|
|
||||||
this.$emit('draw', { area, isTooSmall })
|
this.$emit('draw', { area, isTooSmall })
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.showMask = false
|
this.showMask = false
|
||||||
this.newArea = null
|
this.newAreas = []
|
||||||
},
|
},
|
||||||
rectsOverlap (r1, r2) {
|
rectsOverlap (r1, r2) {
|
||||||
return !(
|
return !(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<span
|
<span
|
||||||
class="dropdown dropdown-end field-settings-dropdown"
|
class="dropdown dropdown-end field-settings-dropdown"
|
||||||
:class="{ 'dropdown-open': ((!field.preferences?.price && !field.preferences?.formula && !field.preferences?.price_id && !field.preferences?.payment_link_id) || !isConnected) && !isLoading }"
|
:class="{ 'dropdown-open': withForceOpen && ((!field.preferences?.price && !field.preferences?.formula && !field.preferences?.price_id && !field.preferences?.payment_link_id) || !isConnected) && !isLoading }"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@@ -231,7 +231,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li class="mt-1">
|
<li
|
||||||
|
v-if="withCondition"
|
||||||
|
class="mt-1"
|
||||||
|
>
|
||||||
<label
|
<label
|
||||||
class="label-text cursor-pointer text-center w-full flex items-center"
|
class="label-text cursor-pointer text-center w-full flex items-center"
|
||||||
@click="$emit('click-condition')"
|
@click="$emit('click-condition')"
|
||||||
@@ -244,12 +247,29 @@
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
<hr
|
||||||
|
v-if="withCustomFields"
|
||||||
|
class="pb-0.5 mt-0.5"
|
||||||
|
>
|
||||||
|
<li v-if="withCustomFields">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="text-sm py-1 px-2"
|
||||||
|
@click.prevent="$emit('add-custom-field', field)"
|
||||||
|
>
|
||||||
|
<IconForms
|
||||||
|
:width="20"
|
||||||
|
:stroke-width="1.6"
|
||||||
|
/>
|
||||||
|
{{ t('save_as_custom_field') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { IconMathFunction, IconSettings, IconCircleCheck, IconInfoCircle, IconBrandStripe, IconInnerShadowTop, IconRouteAltLeft } from '@tabler/icons-vue'
|
import { IconMathFunction, IconSettings, IconCircleCheck, IconInfoCircle, IconBrandStripe, IconInnerShadowTop, IconRouteAltLeft, IconForms } from '@tabler/icons-vue'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
const isConnected = ref(false)
|
const isConnected = ref(false)
|
||||||
@@ -261,6 +281,7 @@ export default {
|
|||||||
IconCircleCheck,
|
IconCircleCheck,
|
||||||
IconRouteAltLeft,
|
IconRouteAltLeft,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
|
IconForms,
|
||||||
IconMathFunction,
|
IconMathFunction,
|
||||||
IconInnerShadowTop,
|
IconInnerShadowTop,
|
||||||
IconBrandStripe
|
IconBrandStripe
|
||||||
@@ -270,9 +291,24 @@ export default {
|
|||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
withForceOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
withCustomFields: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
withCondition: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['click-condition', 'click-description', 'click-formula'],
|
emits: ['click-condition', 'click-description', 'click-formula', 'add-custom-field'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isLoading: false
|
isLoading: false
|
||||||
|
|||||||
@@ -47,12 +47,14 @@ class AccountConfig < ApplicationRecord
|
|||||||
WITH_SIGNATURE_ID_REASON_KEY = 'with_signature_id_reason'
|
WITH_SIGNATURE_ID_REASON_KEY = 'with_signature_id_reason'
|
||||||
RECIPIENT_FORM_FIELDS_KEY = 'recipient_form_fields'
|
RECIPIENT_FORM_FIELDS_KEY = 'recipient_form_fields'
|
||||||
WITH_AUDIT_VALUES_KEY = 'with_audit_values'
|
WITH_AUDIT_VALUES_KEY = 'with_audit_values'
|
||||||
|
WITH_AUDIT_SENDER_KEY = 'with_audit_sender'
|
||||||
WITH_SUBMITTER_TIMEZONE_KEY = 'with_submitter_timezone'
|
WITH_SUBMITTER_TIMEZONE_KEY = 'with_submitter_timezone'
|
||||||
REQUIRE_SIGNING_REASON_KEY = 'require_signing_reason'
|
REQUIRE_SIGNING_REASON_KEY = 'require_signing_reason'
|
||||||
REUSE_SIGNATURE_KEY = 'reuse_signature'
|
REUSE_SIGNATURE_KEY = 'reuse_signature'
|
||||||
WITH_FIELD_LABELS_KEY = 'with_field_labels'
|
WITH_FIELD_LABELS_KEY = 'with_field_labels'
|
||||||
COMBINE_PDF_RESULT_KEY = 'combine_pdf_result_key'
|
COMBINE_PDF_RESULT_KEY = 'combine_pdf_result_key'
|
||||||
DOCUMENT_FILENAME_FORMAT_KEY = 'document_filename_format'
|
DOCUMENT_FILENAME_FORMAT_KEY = 'document_filename_format'
|
||||||
|
TEMPLATE_CUSTOM_FIELDS_KEY = 'template_custom_fields'
|
||||||
POLICY_LINKS_KEY = 'policy_links'
|
POLICY_LINKS_KEY = 'policy_links'
|
||||||
|
|
||||||
DEFAULT_VALUES = {
|
DEFAULT_VALUES = {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<% uuid = local_assigns[:uuid] || SecureRandom.uuid %>
|
<% uuid = local_assigns[:uuid] || SecureRandom.uuid %>
|
||||||
<label id="<%= local_assigns[:button_id] %>" for="<%= uuid %>" class="<%= local_assigns[:btn_class] %>"><%= local_assigns[:btn_text] %></label>
|
|
||||||
<input type="checkbox" id="<%= uuid %>" class="modal-toggle">
|
<input type="checkbox" id="<%= uuid %>" class="modal-toggle">
|
||||||
<div id="<%= local_assigns[:id] %>" class="modal items-start !animate-none overflow-y-auto">
|
<div id="<%= local_assigns[:id] %>" class="modal items-start !animate-none overflow-y-auto">
|
||||||
<div class="modal-box pt-4 pb-6 px-6 mt-20 max-h-none">
|
<div class="modal-box pt-4 pb-6 px-6 mt-20 max-h-none">
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<% link = pagy_anchor(pagy) %>
|
|
||||||
<% if pagy.pages > 1 %>
|
<% if pagy.pages > 1 %>
|
||||||
<div class="flex my-6 justify-center md:justify-between">
|
<div class="flex my-6 justify-center md:justify-between">
|
||||||
<div class="hidden md:block text-sm">
|
<div class="hidden md:block text-sm">
|
||||||
@@ -12,8 +11,8 @@
|
|||||||
<div class="flex items-center space-x-1.5">
|
<div class="flex items-center space-x-1.5">
|
||||||
<%= local_assigns[:right_additional_html] %>
|
<%= local_assigns[:right_additional_html] %>
|
||||||
<div class="join">
|
<div class="join">
|
||||||
<% if pagy.prev %>
|
<% if pagy.previous %>
|
||||||
<%== link.call(pagy.prev, '«', classes: 'join-item btn min-h-full h-10') %>
|
<%= link_to '«', url_for(params: request.query_parameters.merge('page' => pagy.previous)), class: 'join-item btn min-h-full h-10' %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="join-item btn btn-disabled !bg-base-200 min-h-full h-10">«</span>
|
<span class="join-item btn btn-disabled !bg-base-200 min-h-full h-10">«</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -23,7 +22,7 @@
|
|||||||
<% if local_assigns[:next_page_path].present? %>
|
<% if local_assigns[:next_page_path].present? %>
|
||||||
<%= link_to '»', local_assigns[:next_page_path], class: 'join-item btn min-h-full h-10' %>
|
<%= link_to '»', local_assigns[:next_page_path], class: 'join-item btn min-h-full h-10' %>
|
||||||
<% elsif pagy.next %>
|
<% elsif pagy.next %>
|
||||||
<%== link.call(pagy.next, '»', classes: 'join-item btn min-h-full h-10') %>
|
<%= link_to '»', url_for(params: request.query_parameters.merge('page' => pagy.next)), class: 'join-item btn min-h-full h-10' %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="join-item btn btn-disabled !bg-base-200 min-h-full h-10">»</span>
|
<span class="join-item btn btn-disabled !bg-base-200 min-h-full h-10">»</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
<form action="<%= url_for %>" method="get" class="items-center flex">
|
<form action="<%= url_for %>" method="get" class="items-center flex">
|
||||||
<% if params[:status].present? %>
|
|
||||||
<input name="status" value="<%= params[:status] %>" class="hidden">
|
|
||||||
<% end %>
|
|
||||||
<% Submissions::Filter::ALLOWED_PARAMS.each do |key| %>
|
<% Submissions::Filter::ALLOWED_PARAMS.each do |key| %>
|
||||||
<% if params[key].present? %>
|
<% if params[key].present? %>
|
||||||
<input name="<%= key %>" value="<%= params[key] %>" class="hidden">
|
<input name="<%= key %>" value="<%= params[key] %>" class="hidden">
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %>
|
<% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %>
|
||||||
<% schema = Submissions.filtered_conditions_schema(@submitter.submission, values:, include_submitter_uuid: @submitter.uuid) %>
|
<% schema = Submissions.filtered_conditions_schema(@submitter.submission, values:, include_submitter_uuid: @submitter.uuid) %>
|
||||||
<% font_scale = 1000.0 / PdfUtils::US_LETTER_W %>
|
<% font_scale = 1000.0 / PdfUtils::US_LETTER_W %>
|
||||||
|
<% decline_modal_checkbox_uuid = nil %>
|
||||||
<div style="max-height: -webkit-fill-available;">
|
<div style="max-height: -webkit-fill-available;">
|
||||||
<div id="scrollbox">
|
<div id="scrollbox">
|
||||||
<div class="mx-auto block pb-72" style="max-width: 1000px">
|
<div class="mx-auto block pb-72" style="max-width: 1000px">
|
||||||
@@ -20,12 +21,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-2" style="margin-left: 20px; flex-shrink: 0">
|
<div class="flex items-center space-x-2" style="margin-left: 20px; flex-shrink: 0">
|
||||||
<% if @form_configs[:with_decline] %>
|
<% if @form_configs[:with_decline] %>
|
||||||
<% decline_modal_checkbox_uuid = SecureRandom.uuid %>
|
<label id="decline_button" for="<%= decline_modal_checkbox_uuid = SecureRandom.uuid %>" class="btn btn-sm !px-5"><%= t(:decline) %></label>
|
||||||
<div>
|
|
||||||
<%= render 'shared/html_modal', title: t(:decline), btn_text: t(:decline), btn_class: 'btn btn-sm !px-5', button_id: 'decline_button', uuid: decline_modal_checkbox_uuid do %>
|
|
||||||
<%= render 'submit_form/decline_form', submitter: @submitter %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @form_configs[:with_partial_download] %>
|
<% if @form_configs[:with_partial_download] %>
|
||||||
<download-button data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm !px-4">
|
<download-button data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm !px-4">
|
||||||
@@ -102,11 +98,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="fixed bottom-0 w-full h-0 z-20">
|
<div class="fixed bottom-0 w-full h-0 z-50">
|
||||||
<div class="mx-auto" style="max-width: 1000px">
|
<div class="mx-auto" style="max-width: 1000px">
|
||||||
<div class="relative md:mx-32">
|
<div class="relative md:mx-32">
|
||||||
<%= render 'submit_form/submission_form', attachments_index: @attachments_index, submitter: @submitter, signature_attachment: @signature_attachment, configs: @form_configs, dry_run: local_assigns[:dry_run], expand: local_assigns[:expand], scroll_padding: local_assigns.fetch(:scroll_padding, '-110px'), schema: %>
|
<%= render 'submit_form/submission_form', attachments_index: @attachments_index, submitter: @submitter, signature_attachment: @signature_attachment, configs: @form_configs, dry_run: local_assigns[:dry_run], expand: local_assigns[:expand], scroll_padding: local_assigns.fetch(:scroll_padding, '-110px'), schema: %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<% if @form_configs[:with_decline] %>
|
||||||
|
<%= render 'shared/html_modal', title: t(:decline), uuid: decline_modal_checkbox_uuid do %>
|
||||||
|
<%= render 'submit_form/decline_form', submitter: @submitter %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
<%= render 'scripts/autosize_field' %>
|
<%= render 'scripts/autosize_field' %>
|
||||||
|
|||||||
@@ -6,4 +6,4 @@
|
|||||||
<%= button_to nil, user_configs_path, method: :post, params: { user_config: { key: UserConfig::SHOW_APP_TOUR, value: true } }, class: 'hidden', id: 'start_tour_button' %>
|
<%= button_to nil, user_configs_path, method: :post, params: { user_config: { key: UserConfig::SHOW_APP_TOUR, value: true } }, class: 'hidden', id: 'start_tour_button' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<template-builder class="grid" data-template="<%= @template_data %>" data-with-sign-yourself-button="<%= !@template.archived_at? %>" data-with-fields-detection="true" data-with-send-button="<%= !@template.archived_at? && can?(:create, @template.submissions.new(account: current_account)) %>" data-locale="<%= I18n.locale %>" data-show-tour-start-form="<%= @show_tour_start_form %>"></template-builder>
|
<template-builder class="grid" data-template="<%= @template_data %>" data-custom-fields="<%= (current_account.account_configs.find_or_initialize_by(key: AccountConfig::TEMPLATE_CUSTOM_FIELDS_KEY).value || []).to_json %>" data-with-sign-yourself-button="<%= !@template.archived_at? %>" data-with-fields-detection="true" data-with-send-button="<%= !@template.archived_at? && can?(:create, @template.submissions.new(account: current_account)) %>" data-locale="<%= I18n.locale %>" data-show-tour-start-form="<%= @show_tour_start_form %>"></template-builder>
|
||||||
|
|||||||
@@ -105,8 +105,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-1.5">
|
<div class="flex items-center space-x-1.5">
|
||||||
<div class="join">
|
<div class="join">
|
||||||
<% if @pagy.prev %>
|
<% if @pagy.previous %>
|
||||||
<%= link_to '«', url_for(page: @pagy.prev, anchor: 'log'), class: 'join-item btn min-h-full h-10' %>
|
<%= link_to '«', url_for(params: request.query_parameters.merge('page' => @pagy.previous), anchor: 'log'), class: 'join-item btn min-h-full h-10' %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="join-item btn btn-disabled !bg-base-200 min-h-full h-10">«</span>
|
<span class="join-item btn btn-disabled !bg-base-200 min-h-full h-10">«</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
<%= "Page #{@pagy.page}" %>
|
<%= "Page #{@pagy.page}" %>
|
||||||
</span>
|
</span>
|
||||||
<% if @pagy.next %>
|
<% if @pagy.next %>
|
||||||
<%= link_to '»', url_for(page: @pagy.next, anchor: 'log'), class: 'join-item btn min-h-full h-10' %>
|
<%= link_to '»', url_for(params: request.query_parameters.merge('page' => @pagy.next), anchor: 'log'), class: 'join-item btn min-h-full h-10' %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="join-item btn btn-disabled !bg-base-200 min-h-full h-10">»</span>
|
<span class="join-item btn btn-disabled !bg-base-200 min-h-full h-10">»</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Bundler.require(*Rails.groups)
|
|||||||
|
|
||||||
module DocuSeal
|
module DocuSeal
|
||||||
class Application < Rails::Application
|
class Application < Rails::Application
|
||||||
config.load_defaults 8.0
|
config.load_defaults 8.1
|
||||||
|
|
||||||
config.autoload_lib(ignore: %w[assets tasks puma])
|
config.autoload_lib(ignore: %w[assets tasks puma])
|
||||||
|
|
||||||
|
|||||||
+20
-4
@@ -60,12 +60,28 @@ if ENV['RAILS_ENV'] == 'production'
|
|||||||
ENV['DATABASE_URL'] = ENV['DATABASE_URL'].to_s.empty? ? database_url : ENV.fetch('DATABASE_URL', nil)
|
ENV['DATABASE_URL'] = ENV['DATABASE_URL'].to_s.empty? ? database_url : ENV.fetch('DATABASE_URL', nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
unless Process.uid == 2000
|
unless Process.euid == 2000
|
||||||
begin
|
begin
|
||||||
Process::Sys.setgid(2000)
|
test_file = "#{ENV.fetch('WORKDIR', '.')}/test"
|
||||||
Process::Sys.setuid(2000)
|
|
||||||
|
orig_euid = Process.euid
|
||||||
|
orig_egid = Process.egid
|
||||||
|
|
||||||
|
Process::Sys.setegid(2000)
|
||||||
|
Process::Sys.seteuid(2000)
|
||||||
|
|
||||||
|
File.open(test_file, 'w') { true }
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
puts 'Unable to run as 2000:2000'
|
Process::Sys.seteuid(orig_euid)
|
||||||
|
Process::Sys.setegid(orig_egid)
|
||||||
|
|
||||||
|
puts "Unable to run as 2000:2000, running as #{orig_euid}:#{orig_egid}"
|
||||||
|
ensure
|
||||||
|
begin
|
||||||
|
File.unlink(test_file)
|
||||||
|
rescue StandardError
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ Rails.application.configure do
|
|||||||
user_name: ENV.fetch('SMTP_USERNAME', nil),
|
user_name: ENV.fetch('SMTP_USERNAME', nil),
|
||||||
password: ENV.fetch('SMTP_PASSWORD', nil),
|
password: ENV.fetch('SMTP_PASSWORD', nil),
|
||||||
authentication: ENV.fetch('SMTP_PASSWORD', nil).present? ? ENV.fetch('SMTP_AUTHENTICATION', 'plain') : nil,
|
authentication: ENV.fetch('SMTP_PASSWORD', nil).present? ? ENV.fetch('SMTP_AUTHENTICATION', 'plain') : nil,
|
||||||
enable_starttls_auto: ENV['SMTP_ENABLE_STARTTLS_AUTO'] != 'false'
|
enable_starttls: ENV['SMTP_ENABLE_STARTTLS'] != 'false'
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
autoload :CSV, 'csv'
|
||||||
|
autoload :CSVSafe, 'csv-safe'
|
||||||
|
autoload :RubyXL, 'rubyXL'
|
||||||
|
autoload :Zip, 'zip'
|
||||||
|
autoload :Numo, 'numo/narray'
|
||||||
|
autoload :OnnxRuntime, 'onnxruntime'
|
||||||
|
autoload :RQRCode, 'rqrcode'
|
||||||
|
autoload :ArabicLetterConnector, 'arabic-letter-connector/logic'
|
||||||
|
autoload :JWT, 'jwt'
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'csv'
|
|
||||||
@@ -1,10 +1,3 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'pagy/extras/countless'
|
Pagy.options[:limit] = 10
|
||||||
|
|
||||||
Pagy::DEFAULT[:limit] = 10
|
|
||||||
Pagy::DEFAULT.freeze
|
|
||||||
|
|
||||||
ActiveSupport.on_load(:action_view) do
|
|
||||||
include Pagy::Frontend
|
|
||||||
end
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ en: &en
|
|||||||
pro: Pro
|
pro: Pro
|
||||||
thanks: Thanks
|
thanks: Thanks
|
||||||
private: Private
|
private: Private
|
||||||
|
make_all_newly_created_templates_private_to_their_creator_and_admins_by_default: Make all newly created templates private to their creator and admins by default.
|
||||||
|
create_templates_with_admin_access_by_default: Create templates with admin access by default
|
||||||
require_email_2fa: Require email 2FA
|
require_email_2fa: Require email 2FA
|
||||||
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: When checked, each signer must verify their email with a one-time code before accessing the document.
|
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: When checked, each signer must verify their email with a one-time code before accessing the document.
|
||||||
require_phone_2fa: Require phone 2FA
|
require_phone_2fa: Require phone 2FA
|
||||||
@@ -1029,6 +1031,8 @@ es: &es
|
|||||||
stripe_account_has_been_connected: La cuenta de Stripe ha sido conectada.
|
stripe_account_has_been_connected: La cuenta de Stripe ha sido conectada.
|
||||||
re_connect_stripe: Volver a conectar Stripe
|
re_connect_stripe: Volver a conectar Stripe
|
||||||
private: Privado
|
private: Privado
|
||||||
|
make_all_newly_created_templates_private_to_their_creator_and_admins_by_default: Hacer que todas las plantillas recién creadas sean privadas para su creador y los administradores por defecto.
|
||||||
|
create_templates_with_admin_access_by_default: Crear plantillas con acceso de administrador por defecto
|
||||||
require_email_2fa: Requerir 2FA por correo electrónico
|
require_email_2fa: Requerir 2FA por correo electrónico
|
||||||
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Cuando está marcado, cada firmante debe verificar su correo electrónico con un código de un solo uso antes de acceder al documento.
|
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Cuando está marcado, cada firmante debe verificar su correo electrónico con un código de un solo uso antes de acceder al documento.
|
||||||
require_phone_2fa: Requerir 2FA por teléfono
|
require_phone_2fa: Requerir 2FA por teléfono
|
||||||
@@ -2011,6 +2015,8 @@ it: &it
|
|||||||
stripe_account_has_been_connected: L'account Stripe è stato collegato.
|
stripe_account_has_been_connected: L'account Stripe è stato collegato.
|
||||||
re_connect_stripe: Ricollega Stripe
|
re_connect_stripe: Ricollega Stripe
|
||||||
private: Privato
|
private: Privato
|
||||||
|
make_all_newly_created_templates_private_to_their_creator_and_admins_by_default: Rendere tutte le nuove template private per il creatore e gli amministratori per impostazione predefinita.
|
||||||
|
create_templates_with_admin_access_by_default: Crea modelli con accesso amministratore per impostazione predefinita
|
||||||
require_email_2fa: Richiedi 2FA email
|
require_email_2fa: Richiedi 2FA email
|
||||||
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Quando selezionato, ogni firmatario deve verificare la propria email con un codice monouso prima di accedere al documento.
|
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Quando selezionato, ogni firmatario deve verificare la propria email con un codice monouso prima di accedere al documento.
|
||||||
require_phone_2fa: Richiedi 2FA telefono
|
require_phone_2fa: Richiedi 2FA telefono
|
||||||
@@ -2994,6 +3000,8 @@ fr: &fr
|
|||||||
stripe_account_has_been_connected: Le compte Stripe a été connecté.
|
stripe_account_has_been_connected: Le compte Stripe a été connecté.
|
||||||
re_connect_stripe: Reconnecter Stripe
|
re_connect_stripe: Reconnecter Stripe
|
||||||
private: Privé
|
private: Privé
|
||||||
|
make_all_newly_created_templates_private_to_their_creator_and_admins_by_default: Rendre tous les nouveaux modèles privés pour leur créateur et les administrateurs par défaut.
|
||||||
|
create_templates_with_admin_access_by_default: Créer des modèles avec un accès administrateur par défaut
|
||||||
require_email_2fa: Exiger la 2FA par email
|
require_email_2fa: Exiger la 2FA par email
|
||||||
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Lorsque coché, chaque signataire doit vérifier son email avec un code à usage unique avant d'accéder au document.
|
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Lorsque coché, chaque signataire doit vérifier son email avec un code à usage unique avant d'accéder au document.
|
||||||
require_phone_2fa: Exiger la 2FA par téléphone
|
require_phone_2fa: Exiger la 2FA par téléphone
|
||||||
@@ -3973,6 +3981,8 @@ pt: &pt
|
|||||||
stripe_account_has_been_connected: Conta Stripe foi conectada.
|
stripe_account_has_been_connected: Conta Stripe foi conectada.
|
||||||
re_connect_stripe: Reconectar Stripe
|
re_connect_stripe: Reconectar Stripe
|
||||||
private: Privado
|
private: Privado
|
||||||
|
make_all_newly_created_templates_private_to_their_creator_and_admins_by_default: Tornar todos os modelos recém-criados privados para seu criador e administradores por padrão.
|
||||||
|
create_templates_with_admin_access_by_default: Criar modelos com acesso de administrador por padrão
|
||||||
require_email_2fa: Exigir 2FA por email
|
require_email_2fa: Exigir 2FA por email
|
||||||
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Quando marcado, cada signatário deve verificar seu email com um código de uso único antes de acessar o documento.
|
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Quando marcado, cada signatário deve verificar seu email com um código de uso único antes de acessar o documento.
|
||||||
require_phone_2fa: Exigir 2FA por telefone
|
require_phone_2fa: Exigir 2FA por telefone
|
||||||
@@ -4941,6 +4951,8 @@ de: &de
|
|||||||
pro: Pro
|
pro: Pro
|
||||||
thanks: Danke
|
thanks: Danke
|
||||||
private: Privat
|
private: Privat
|
||||||
|
make_all_newly_created_templates_private_to_their_creator_and_admins_by_default: Alle neu erstellten Vorlagen standardmäßig nur für ihren Ersteller und Administratoren sichtbar machen.
|
||||||
|
create_templates_with_admin_access_by_default: Vorlagen standardmäßig mit Administratorzugriff erstellen
|
||||||
require_email_2fa: E-Mail 2FA erforderlich
|
require_email_2fa: E-Mail 2FA erforderlich
|
||||||
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Wenn aktiviert, muss jeder Unterzeichner seine E-Mail mit einem einmaligen Code verifizieren, bevor er auf das Dokument zugreifen kann.
|
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Wenn aktiviert, muss jeder Unterzeichner seine E-Mail mit einem einmaligen Code verifizieren, bevor er auf das Dokument zugreifen kann.
|
||||||
require_phone_2fa: Telefon 2FA erforderlich
|
require_phone_2fa: Telefon 2FA erforderlich
|
||||||
@@ -6311,6 +6323,8 @@ nl: &nl
|
|||||||
pro: Pro
|
pro: Pro
|
||||||
thanks: Bedankt
|
thanks: Bedankt
|
||||||
private: Privé
|
private: Privé
|
||||||
|
make_all_newly_created_templates_private_to_their_creator_and_admins_by_default: Maak alle nieuw aangemaakte sjablonen standaard privé voor hun maker en admins.
|
||||||
|
create_templates_with_admin_access_by_default: Sjablonen standaard met admin-toegang maken
|
||||||
require_email_2fa: E-mail 2FA vereist
|
require_email_2fa: E-mail 2FA vereist
|
||||||
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Wanneer aangevinkt, moet elke ondertekenaar zijn e-mail verifiëren met een eenmalige code voordat hij toegang krijgt tot het document.
|
when_checked_each_signer_must_verify_their_email_with_a_one_time_code_before_accessing_the_document: Wanneer aangevinkt, moet elke ondertekenaar zijn e-mail verifiëren met een eenmalige code voordat hij toegang krijgt tot het document.
|
||||||
require_phone_2fa: Telefoon 2FA vereist
|
require_phone_2fa: Telefoon 2FA vereist
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ Rails.application.routes.draw do
|
|||||||
resources :verify_pdf_signature, only: %i[create]
|
resources :verify_pdf_signature, only: %i[create]
|
||||||
resource :mfa_setup, only: %i[show new edit create destroy], controller: 'mfa_setup'
|
resource :mfa_setup, only: %i[show new edit create destroy], controller: 'mfa_setup'
|
||||||
resources :account_configs, only: %i[create destroy]
|
resources :account_configs, only: %i[create destroy]
|
||||||
|
resources :account_custom_fields, only: %i[create]
|
||||||
resources :user_configs, only: %i[create]
|
resources :user_configs, only: %i[create]
|
||||||
resources :encrypted_user_configs, only: %i[destroy]
|
resources :encrypted_user_configs, only: %i[destroy]
|
||||||
resources :timestamp_server, only: %i[create]
|
resources :timestamp_server, only: %i[create]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ default: &default
|
|||||||
shakapacker_precompile: true
|
shakapacker_precompile: true
|
||||||
webpack_compile_output: true
|
webpack_compile_output: true
|
||||||
additional_paths: []
|
additional_paths: []
|
||||||
webpack_loader: 'babel'
|
javascript_transpiler: 'babel'
|
||||||
compiler_strategy: digest
|
compiler_strategy: digest
|
||||||
cache_manifest: false
|
cache_manifest: false
|
||||||
ensure_consistent_versioning: false
|
ensure_consistent_versioning: false
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ google:
|
|||||||
cache_control: "public, max-age=31536000"
|
cache_control: "public, max-age=31536000"
|
||||||
|
|
||||||
azure:
|
azure:
|
||||||
service: AzureStorage
|
service: AzureBlob
|
||||||
storage_account_name: <%= ENV['AZURE_STORAGE_ACCOUNT_NAME'] %>
|
storage_account_name: <%= ENV['AZURE_STORAGE_ACCOUNT_NAME'] %>
|
||||||
storage_access_key: <%= ENV['AZURE_STORAGE_ACCESS_KEY'] %>
|
storage_access_key: <%= ENV['AZURE_STORAGE_ACCESS_KEY'] %>
|
||||||
container: <%= ENV['AZURE_CONTAINER'] %>
|
container: <%= ENV['AZURE_CONTAINER'] %>
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ module ActionMailerConfigsInterceptor
|
|||||||
def build_smtp_configs_hash(email_configs)
|
def build_smtp_configs_hash(email_configs)
|
||||||
value = email_configs.value
|
value = email_configs.value
|
||||||
|
|
||||||
|
is_tls = value['security'] == 'tls' || (value['security'].blank? && value['port'].to_s == '465')
|
||||||
|
is_ssl = value['security'] == 'ssl'
|
||||||
|
|
||||||
{
|
{
|
||||||
user_name: value['username'],
|
user_name: value['username'],
|
||||||
password: value['password'],
|
password: value['password'],
|
||||||
@@ -53,11 +56,11 @@ module ActionMailerConfigsInterceptor
|
|||||||
domain: value['domain'],
|
domain: value['domain'],
|
||||||
openssl_verify_mode: value['security'] == 'noverify' ? OpenSSL::SSL::VERIFY_NONE : nil,
|
openssl_verify_mode: value['security'] == 'noverify' ? OpenSSL::SSL::VERIFY_NONE : nil,
|
||||||
authentication: value['password'].present? ? value.fetch('authentication', 'plain') : nil,
|
authentication: value['password'].present? ? value.fetch('authentication', 'plain') : nil,
|
||||||
enable_starttls_auto: value['security'] != 'tls',
|
enable_starttls: !is_tls && !is_ssl,
|
||||||
open_timeout: OPEN_TIMEOUT,
|
open_timeout: OPEN_TIMEOUT,
|
||||||
read_timeout: READ_TIMEOUT,
|
read_timeout: READ_TIMEOUT,
|
||||||
ssl: value['security'] == 'ssl',
|
ssl: is_ssl,
|
||||||
tls: value['security'] == 'tls' || (value['security'].blank? && value['port'].to_s == '465')
|
tls: is_tls
|
||||||
}.compact_blank
|
}.compact_blank
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+1
-3
@@ -364,9 +364,7 @@ class Pdfium
|
|||||||
@closed
|
@closed
|
||||||
end
|
end
|
||||||
|
|
||||||
def form_handle
|
delegate :form_handle, to: :@document
|
||||||
@document.form_handle
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_not_closed!
|
def ensure_not_closed!
|
||||||
raise PdfiumError, 'Page is closed.' if closed?
|
raise PdfiumError, 'Page is closed.' if closed?
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Puma::Plugin.create do
|
|||||||
|
|
||||||
@puma_pid = $PROCESS_ID
|
@puma_pid = $PROCESS_ID
|
||||||
|
|
||||||
launcher.events.on_booted do
|
launcher.events.after_booted do
|
||||||
@redis_server_pid = fork_redis
|
@redis_server_pid = fork_redis
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -19,8 +19,8 @@ Puma::Plugin.create do
|
|||||||
stop_redis_server if Process.pid == @puma_pid
|
stop_redis_server if Process.pid == @puma_pid
|
||||||
end
|
end
|
||||||
|
|
||||||
launcher.events.on_stopped { stop_redis_server }
|
launcher.events.after_stopped { stop_redis_server }
|
||||||
launcher.events.on_restart { stop_redis_server }
|
launcher.events.before_restart { stop_redis_server }
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ Puma::Plugin.create do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def start(launcher)
|
def start(launcher)
|
||||||
launcher.events.on_booted do
|
launcher.events.after_booted do
|
||||||
next if Puma.stats_hash[:workers].to_i != 0
|
next if Puma.stats_hash[:workers].to_i != 0
|
||||||
|
|
||||||
start_sidekiq!
|
start_sidekiq!
|
||||||
end
|
end
|
||||||
|
|
||||||
launcher.events.on_stopped { Thread.new { @sidekiq&.stop }.join }
|
launcher.events.after_stopped { Thread.new { @sidekiq&.stop }.join }
|
||||||
launcher.events.on_restart { Thread.new { @sidekiq&.stop }.join }
|
launcher.events.before_restart { Thread.new { @sidekiq&.stop }.join }
|
||||||
end
|
end
|
||||||
|
|
||||||
def fire_event(config, event)
|
def fire_event(config, event)
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ module Submissions
|
|||||||
next if item['invite_by_uuid'].blank? && item['optional_invite_by_uuid'].blank?
|
next if item['invite_by_uuid'].blank? && item['optional_invite_by_uuid'].blank?
|
||||||
next if submission.template_submitters.any? { |e| e['uuid'] == item['uuid'] }
|
next if submission.template_submitters.any? { |e| e['uuid'] == item['uuid'] }
|
||||||
|
|
||||||
|
item = item.merge('order' => submitter_attr['order']) if submitter_attr && submitter_attr['order'].present?
|
||||||
|
|
||||||
if index.zero?
|
if index.zero?
|
||||||
submission.template_submitters.insert(1, item)
|
submission.template_submitters.insert(1, item)
|
||||||
elsif submission.template_submitters.size > index
|
elsif submission.template_submitters.size > index
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ module Submissions
|
|||||||
total_wait_time ||= 0
|
total_wait_time ||= 0
|
||||||
key = ['result_attachments', submitter.id].join(':')
|
key = ['result_attachments', submitter.id].join(':')
|
||||||
|
|
||||||
return submitter.documents if ApplicationRecord.uncached { LockEvent.exists?(key:, event_name: :complete) }
|
return submitter.documents.reset if ApplicationRecord.uncached { LockEvent.exists?(key:, event_name: :complete) }
|
||||||
|
|
||||||
events = ApplicationRecord.uncached { LockEvent.where(key:).order(:id).to_a }
|
events = ApplicationRecord.uncached { LockEvent.where(key:).order(:id).to_a }
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ module Submissions
|
|||||||
LockEvent.where(key: ['result_attachments', submitter.id].join(':')).order(:id).last
|
LockEvent.where(key: ['result_attachments', submitter.id].join(':')).order(:id).last
|
||||||
end
|
end
|
||||||
|
|
||||||
break submitter.documents.reload if last_event.event_name.in?(%w[complete fail])
|
break submitter.documents.reset if last_event.event_name.in?(%w[complete fail])
|
||||||
|
|
||||||
raise WaitForCompleteTimeout if total_wait_time > CHECK_COMPLETE_TIMEOUT
|
raise WaitForCompleteTimeout if total_wait_time > CHECK_COMPLETE_TIMEOUT
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ module Submissions
|
|||||||
configs = submission.account.account_configs.where(key: [AccountConfig::WITH_AUDIT_VALUES_KEY,
|
configs = submission.account.account_configs.where(key: [AccountConfig::WITH_AUDIT_VALUES_KEY,
|
||||||
AccountConfig::WITH_SIGNATURE_ID,
|
AccountConfig::WITH_SIGNATURE_ID,
|
||||||
AccountConfig::WITH_FILE_LINKS_KEY,
|
AccountConfig::WITH_FILE_LINKS_KEY,
|
||||||
|
AccountConfig::WITH_AUDIT_SENDER_KEY,
|
||||||
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY])
|
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY])
|
||||||
|
|
||||||
last_submitter = submission.submitters.select(&:completed_at).max_by(&:completed_at)
|
last_submitter = submission.submitters.select(&:completed_at).max_by(&:completed_at)
|
||||||
@@ -123,6 +124,7 @@ module Submissions
|
|||||||
with_signature_id = configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID }&.value == true
|
with_signature_id = configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID }&.value == true
|
||||||
with_file_links = configs.find { |c| c.key == AccountConfig::WITH_FILE_LINKS_KEY }&.value == true
|
with_file_links = configs.find { |c| c.key == AccountConfig::WITH_FILE_LINKS_KEY }&.value == true
|
||||||
with_audit_values = configs.find { |c| c.key == AccountConfig::WITH_AUDIT_VALUES_KEY }&.value != false
|
with_audit_values = configs.find { |c| c.key == AccountConfig::WITH_AUDIT_VALUES_KEY }&.value != false
|
||||||
|
with_audit_sender = configs.find { |c| c.key == AccountConfig::WITH_AUDIT_SENDER_KEY }&.value == true
|
||||||
with_submitter_timezone = configs.find { |c| c.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true
|
with_submitter_timezone = configs.find { |c| c.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true
|
||||||
|
|
||||||
timezone = account.timezone
|
timezone = account.timezone
|
||||||
@@ -464,6 +466,11 @@ module Submissions
|
|||||||
name].join(' ')
|
name].join(' ')
|
||||||
I18n.t('submission_event_names.invite_party_by_html', invited_submitter_name:,
|
I18n.t('submission_event_names.invite_party_by_html', invited_submitter_name:,
|
||||||
submitter_name:)
|
submitter_name:)
|
||||||
|
elsif with_audit_sender && (event.event_type == 'send_email' || event.event_type == 'send_sms')
|
||||||
|
[
|
||||||
|
I18n.t("submission_event_names.#{event.event_type}_to_html", submitter_name:),
|
||||||
|
"<b>#{I18n.t(:from)}</b> #{submission.created_by_user.full_name} #{submission.created_by_user.email}"
|
||||||
|
].join("\n")
|
||||||
elsif event.event_type.include?('send_')
|
elsif event.event_type.include?('send_')
|
||||||
I18n.t("submission_event_names.#{event.event_type}_to_html", submitter_name:)
|
I18n.t("submission_event_names.#{event.event_type}_to_html", submitter_name:)
|
||||||
else
|
else
|
||||||
@@ -472,11 +479,20 @@ module Submissions
|
|||||||
|
|
||||||
bold_text, normal_text = text.match(%r{<b>(.*?)</b>(.*)}).captures
|
bold_text, normal_text = text.match(%r{<b>(.*?)</b>(.*)}).captures
|
||||||
|
|
||||||
|
text_box = [{ text: bold_text, font: [FONT_NAME, { variant: :bold }] }, normal_text]
|
||||||
|
|
||||||
|
if text.include?("\n")
|
||||||
|
text_box = text.split("\n")[1..].reduce(text_box) do |acc, row|
|
||||||
|
bold_text, normal_text = row.match(%r{<b>(.*?)</b>(.*)}).captures
|
||||||
|
|
||||||
|
[*acc, "\n", { text: bold_text, font: [FONT_NAME, { variant: :bold }] }, normal_text]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
[
|
[
|
||||||
"#{I18n.l(event.event_timestamp.in_time_zone(timezone), format: :long, locale: account.locale)} " \
|
"#{I18n.l(event.event_timestamp.in_time_zone(timezone), format: :long, locale: account.locale)} " \
|
||||||
"#{TimeUtils.timezone_abbr(timezone, event.event_timestamp)}",
|
"#{TimeUtils.timezone_abbr(timezone, event.event_timestamp)}",
|
||||||
composer.document.layout.formatted_text_box([{ text: bold_text, font: [FONT_NAME, { variant: :bold }] },
|
composer.document.layout.formatted_text_box(text_box)
|
||||||
normal_text])
|
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ module Submissions
|
|||||||
width = page.box.width
|
width = page.box.width
|
||||||
height = page.box.height
|
height = page.box.height
|
||||||
|
|
||||||
preferences_font_size = field.dig('preferences', 'font_size').then { |num| num.present? ? num.to_i : nil }
|
preferences_font_size = field.dig('preferences', 'font_size').then { |num| num.presence&.to_i }
|
||||||
|
|
||||||
font_size = preferences_font_size
|
font_size = preferences_font_size
|
||||||
font_size ||= (([page.box.width, page.box.height].min / A4_SIZE[0].to_f) * FONT_SIZE).to_i
|
font_size ||= (([page.box.width, page.box.height].min / A4_SIZE[0].to_f) * FONT_SIZE).to_i
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ module Submissions
|
|||||||
conn = Faraday.new(uri.origin) do |c|
|
conn = Faraday.new(uri.origin) do |c|
|
||||||
c.options.read_timeout = TIMEOUT
|
c.options.read_timeout = TIMEOUT
|
||||||
c.options.open_timeout = TIMEOUT
|
c.options.open_timeout = TIMEOUT
|
||||||
c.basic_auth(uri.user, uri.password) if uri.password.present?
|
c.request :authorization, :basic, uri.user, uri.password if uri.password.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
response = conn.post(uri.request_uri, build_payload(digest.digest),
|
response = conn.post(uri.request_uri, build_payload(digest.digest),
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ module Submitters
|
|||||||
def serialize_events(events)
|
def serialize_events(events)
|
||||||
events.map do |event|
|
events.map do |event|
|
||||||
event.as_json(only: %i[id submitter_id event_type event_timestamp])
|
event.as_json(only: %i[id submitter_id event_type event_timestamp])
|
||||||
.merge('data' => event.data.slice('reason', 'firstname', 'lastname', 'method', 'country'))
|
.merge('data' => event.data.slice('reason', 'firstname', 'lastname', 'method', 'country', 'idcode'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+13
-11
@@ -22,34 +22,36 @@
|
|||||||
"canvas-confetti": "^1.6.0",
|
"canvas-confetti": "^1.6.0",
|
||||||
"chart.js": "^4.5.1",
|
"chart.js": "^4.5.1",
|
||||||
"codemirror": "^6.0.2",
|
"codemirror": "^6.0.2",
|
||||||
"compression-webpack-plugin": "10.0.0",
|
"compression-webpack-plugin": "11.1.0",
|
||||||
"css-loader": "^6.7.3",
|
"css-loader": "^7.1.2",
|
||||||
"css-minimizer-webpack-plugin": "^5.0.0",
|
"css-minimizer-webpack-plugin": "^5.0.0",
|
||||||
"daisyui": "^3.9.4",
|
"daisyui": "^3.9.4",
|
||||||
"driver.js": "^1.3.5",
|
"driver.js": "^1.3.5",
|
||||||
"mathjs": "^12.4.0",
|
"mathjs": "^12.4.0",
|
||||||
"mini-css-extract-plugin": "^2.7.5",
|
"mini-css-extract-plugin": "^2.10.0",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
"postcss-import": "^15.1.0",
|
"postcss-import": "^15.1.0",
|
||||||
"postcss-loader": "^7.3.0",
|
"postcss-loader": "^7.3.0",
|
||||||
"qr-creator": "^1.0.0",
|
"qr-creator": "^1.0.0",
|
||||||
"rollbar": "^2.26.4",
|
"rollbar": "^2.26.4",
|
||||||
"sass": "^1.62.1",
|
"sass": "^1.62.1",
|
||||||
"sass-loader": "^13.2.2",
|
"sass-loader": "^16.0.6",
|
||||||
"shakapacker": "8.0.0",
|
"shakapacker": "9.5.0",
|
||||||
"signature_pad": "^4.1.5",
|
"signature_pad": "^4.1.5",
|
||||||
"snarkdown": "^2.0.0",
|
"snarkdown": "^2.0.0",
|
||||||
|
"style-loader": "^4.0.0",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"terser-webpack-plugin": "5.3.8",
|
"terser-webpack-plugin": "5.3.16",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vue": "^3.3.2",
|
"vue": "^3.3.2",
|
||||||
"vue-loader": "^17.1.1",
|
"vue-loader": "^17.1.1",
|
||||||
"webpack": "5.94.0",
|
"webpack": "5.104.1",
|
||||||
"webpack-assets-manifest": "5",
|
"webpack-assets-manifest": "6.5.0",
|
||||||
"webpack-bundle-analyzer": "^4.7.0",
|
"webpack-bundle-analyzer": "^4.7.0",
|
||||||
"webpack-cli": "5.1.1",
|
"webpack-cli": "6.0.1",
|
||||||
"webpack-dev-server": "^4.15.0",
|
"webpack-dev-server": "^5.2.3",
|
||||||
"webpack-merge": "5"
|
"webpack-merge": "6.0.1",
|
||||||
|
"webpack-subresource-integrity": "^5.1.0"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@1.0",
|
"packageManager": "yarn@1.0",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user