Merge from docusealco/wip
This commit is contained in:
+8
-1
@@ -84,7 +84,7 @@ RSpec/AnyInstance:
|
|||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Metrics/BlockNesting:
|
Metrics/BlockNesting:
|
||||||
Max: 5
|
Max: 6
|
||||||
|
|
||||||
Rails/I18nLocaleTexts:
|
Rails/I18nLocaleTexts:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
@@ -106,3 +106,10 @@ Rails/StrongParametersExpect:
|
|||||||
|
|
||||||
Rails/RedirectBackOrTo:
|
Rails/RedirectBackOrTo:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/UnknownEnv:
|
||||||
|
Environments:
|
||||||
|
- development
|
||||||
|
- test
|
||||||
|
- production
|
||||||
|
- local
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ ENV RAILS_ENV=production
|
|||||||
ENV BUNDLE_WITHOUT="development:test"
|
ENV BUNDLE_WITHOUT="development:test"
|
||||||
ENV LD_PRELOAD=/lib/libgcompat.so.0
|
ENV LD_PRELOAD=/lib/libgcompat.so.0
|
||||||
ENV OPENSSL_CONF=/etc/openssl_legacy.cnf
|
ENV OPENSSL_CONF=/etc/openssl_legacy.cnf
|
||||||
|
ENV VIPS_MAX_COORD=10000
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ gem 'pretender'
|
|||||||
gem 'puma', require: false
|
gem 'puma', require: false
|
||||||
gem 'rack'
|
gem 'rack'
|
||||||
gem 'rails'
|
gem 'rails'
|
||||||
gem 'rails_autolink'
|
|
||||||
gem 'rails-i18n'
|
gem 'rails-i18n'
|
||||||
gem 'rotp'
|
gem 'rotp'
|
||||||
gem 'rouge', require: false
|
gem 'rouge', require: false
|
||||||
|
|||||||
+6
-15
@@ -219,7 +219,6 @@ GEM
|
|||||||
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.3)
|
|
||||||
ffi (1.17.3-aarch64-linux-gnu)
|
ffi (1.17.3-aarch64-linux-gnu)
|
||||||
ffi (1.17.3-aarch64-linux-musl)
|
ffi (1.17.3-aarch64-linux-musl)
|
||||||
ffi (1.17.3-arm64-darwin)
|
ffi (1.17.3-arm64-darwin)
|
||||||
@@ -338,22 +337,20 @@ GEM
|
|||||||
net-smtp (0.5.1)
|
net-smtp (0.5.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.5)
|
nio4r (2.7.5)
|
||||||
nokogiri (1.19.0-aarch64-linux-gnu)
|
nokogiri (1.19.1-aarch64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.19.0-aarch64-linux-musl)
|
nokogiri (1.19.1-aarch64-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.19.0-arm64-darwin)
|
nokogiri (1.19.1-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.19.0-x86_64-linux-gnu)
|
nokogiri (1.19.1-x86_64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.19.0-x86_64-linux-musl)
|
nokogiri (1.19.1-x86_64-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
numo-narray-alt (0.9.13)
|
numo-narray-alt (0.9.13)
|
||||||
oj (3.16.13)
|
oj (3.16.13)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
ostruct (>= 0.2)
|
ostruct (>= 0.2)
|
||||||
onnxruntime (0.10.1)
|
|
||||||
ffi
|
|
||||||
onnxruntime (0.10.1-aarch64-linux)
|
onnxruntime (0.10.1-aarch64-linux)
|
||||||
ffi
|
ffi
|
||||||
onnxruntime (0.10.1-arm64-darwin)
|
onnxruntime (0.10.1-arm64-darwin)
|
||||||
@@ -372,7 +369,6 @@ GEM
|
|||||||
parser (3.3.10.1)
|
parser (3.3.10.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
pg (1.6.3)
|
|
||||||
pg (1.6.3-aarch64-linux)
|
pg (1.6.3-aarch64-linux)
|
||||||
pg (1.6.3-aarch64-linux-musl)
|
pg (1.6.3-aarch64-linux-musl)
|
||||||
pg (1.6.3-arm64-darwin)
|
pg (1.6.3-arm64-darwin)
|
||||||
@@ -405,7 +401,7 @@ GEM
|
|||||||
puma (7.2.0)
|
puma (7.2.0)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.8.1)
|
racc (1.8.1)
|
||||||
rack (3.2.4)
|
rack (3.2.5)
|
||||||
rack-proxy (0.7.7)
|
rack-proxy (0.7.7)
|
||||||
rack
|
rack
|
||||||
rack-session (2.1.1)
|
rack-session (2.1.1)
|
||||||
@@ -439,10 +435,6 @@ GEM
|
|||||||
rails-i18n (8.1.0)
|
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)
|
|
||||||
actionview (> 3.1)
|
|
||||||
activesupport (> 3.1)
|
|
||||||
railties (> 3.1)
|
|
||||||
railties (8.1.2)
|
railties (8.1.2)
|
||||||
actionpack (= 8.1.2)
|
actionpack (= 8.1.2)
|
||||||
activesupport (= 8.1.2)
|
activesupport (= 8.1.2)
|
||||||
@@ -662,7 +654,6 @@ DEPENDENCIES
|
|||||||
rack
|
rack
|
||||||
rails
|
rails
|
||||||
rails-i18n
|
rails-i18n
|
||||||
rails_autolink
|
|
||||||
rotp
|
rotp
|
||||||
rouge
|
rouge
|
||||||
rqrcode
|
rqrcode
|
||||||
|
|||||||
@@ -172,7 +172,10 @@ module Api
|
|||||||
Submissions::NormalizeParamUtils.save_default_value_attachments!(attachments, submitters)
|
Submissions::NormalizeParamUtils.save_default_value_attachments!(attachments, submitters)
|
||||||
|
|
||||||
submitters.each do |submitter|
|
submitters.each do |submitter|
|
||||||
SubmissionEvents.create_with_tracking_data(submitter, 'api_complete_form', request) if submitter.completed_at?
|
if submitter.completed_at?
|
||||||
|
Submitters::SubmitValues.maybe_invite_via_field(submitter, request)
|
||||||
|
SubmissionEvents.create_with_tracking_data(submitter, 'api_complete_form', request)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
submissions
|
submissions
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ module Api
|
|||||||
render json: Submitters::SerializeForApi.call(@submitter, with_template: true, with_events: true, params:)
|
render json: Submitters::SerializeForApi.call(@submitter, with_template: true, with_events: true, params:)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/MethodLength
|
||||||
def update
|
def update
|
||||||
if @submitter.completed_at?
|
if @submitter.completed_at?
|
||||||
return render json: { error: 'Submitter has already completed the submission.' }, status: :unprocessable_content
|
return render json: { error: 'Submitter has already completed the submission.' }, status: :unprocessable_content
|
||||||
@@ -60,7 +61,10 @@ module Api
|
|||||||
|
|
||||||
@submitter.submission.save!
|
@submitter.submission.save!
|
||||||
|
|
||||||
SubmissionEvents.create_with_tracking_data(@submitter, 'api_complete_form', request) if @submitter.completed_at?
|
if @submitter.completed_at?
|
||||||
|
Submitters::SubmitValues.maybe_invite_via_field(@submitter, request)
|
||||||
|
SubmissionEvents.create_with_tracking_data(@submitter, 'api_complete_form', request)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if @submitter.completed_at?
|
if @submitter.completed_at?
|
||||||
@@ -78,6 +82,7 @@ module Api
|
|||||||
|
|
||||||
render json: { error: e.message }, status: :unprocessable_content
|
render json: { error: e.message }, status: :unprocessable_content
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
def submitter_params
|
def submitter_params
|
||||||
submitter_params = params.key?(:submitter) ? params.require(:submitter) : params
|
submitter_params = params.key?(:submitter) ? params.require(:submitter) : params
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ module Api
|
|||||||
:external_id,
|
:external_id,
|
||||||
:shared_link,
|
:shared_link,
|
||||||
{
|
{
|
||||||
submitters: [%i[name uuid is_requester invite_by_uuid optional_invite_by_uuid linked_to_uuid email order]],
|
submitters: [%i[name uuid is_requester invite_by_uuid invite_via_field_uuid
|
||||||
|
optional_invite_by_uuid linked_to_uuid email order]],
|
||||||
fields: [[:uuid, :submitter_uuid, :name, :type,
|
fields: [[:uuid, :submitter_uuid, :name, :type,
|
||||||
:required, :readonly, :default_value,
|
:required, :readonly, :default_value,
|
||||||
:title, :description, :prefillable,
|
:title, :description, :prefillable,
|
||||||
|
|||||||
@@ -42,10 +42,6 @@ class ApplicationController < ActionController::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def default_url_options
|
def default_url_options
|
||||||
if request.domain == 'docuseal.com'
|
|
||||||
return { host: 'docuseal.com', protocol: ENV['FORCE_SSL'].present? ? 'https' : 'http' }
|
|
||||||
end
|
|
||||||
|
|
||||||
Docuseal.default_url_options
|
Docuseal.default_url_options
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class SubmissionsDownloadController < ApplicationController
|
|||||||
key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY)&.value
|
key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY)&.value
|
||||||
|
|
||||||
Submitters.select_attachments_for_download(submitter).map do |attachment|
|
Submitters.select_attachments_for_download(submitter).map do |attachment|
|
||||||
ActiveStorage::Blob.proxy_url(
|
ActiveStorage::Blob.proxy_path(
|
||||||
attachment.blob,
|
attachment.blob,
|
||||||
expires_at: FILES_TTL.from_now.to_i,
|
expires_at: FILES_TTL.from_now.to_i,
|
||||||
filename: Submitters.build_document_filename(submitter, attachment.blob, filename_format)
|
filename: Submitters.build_document_filename(submitter, attachment.blob, filename_format)
|
||||||
@@ -83,7 +83,7 @@ class SubmissionsDownloadController < ApplicationController
|
|||||||
filename_format = AccountConfig.find_or_initialize_by(account_id: submitter.account_id,
|
filename_format = AccountConfig.find_or_initialize_by(account_id: submitter.account_id,
|
||||||
key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY)&.value
|
key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY)&.value
|
||||||
|
|
||||||
ActiveStorage::Blob.proxy_url(
|
ActiveStorage::Blob.proxy_path(
|
||||||
attachment.blob,
|
attachment.blob,
|
||||||
expires_at: FILES_TTL.from_now.to_i,
|
expires_at: FILES_TTL.from_now.to_i,
|
||||||
filename: Submitters.build_document_filename(submitter, attachment.blob, filename_format)
|
filename: Submitters.build_document_filename(submitter, attachment.blob, filename_format)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class SubmitFormDownloadController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
urls = attachments.map do |attachment|
|
urls = attachments.map do |attachment|
|
||||||
ActiveStorage::Blob.proxy_url(attachment.blob, expires_at: FILES_TTL.from_now.to_i)
|
ActiveStorage::Blob.proxy_path(attachment.blob, expires_at: FILES_TTL.from_now.to_i)
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: urls
|
render json: urls
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ class SubmitFormInviteController < ApplicationController
|
|||||||
next unless attrs
|
next unless attrs
|
||||||
next if attrs[:email].blank?
|
next if attrs[:email].blank?
|
||||||
|
|
||||||
submitter.submission.submitters.create!(**attrs, account_id: submitter.account_id)
|
email = Submissions.normalize_email(attrs[:email])
|
||||||
|
|
||||||
|
submitter.submission.submitters.create!(uuid: attrs[:uuid], email:, account_id: submitter.account_id)
|
||||||
|
|
||||||
SubmissionEvents.create_with_tracking_data(submitter, 'invite_party', request, { uuid: submitter.uuid })
|
SubmissionEvents.create_with_tracking_data(submitter, 'invite_party', request, { uuid: submitter.uuid })
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class TemplateDocumentsController < ApplicationController
|
|||||||
FILES_TTL = 5.minutes
|
FILES_TTL = 5.minutes
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @template.schema_documents.map { |d| ActiveStorage::Blob.proxy_url(d.blob, expires_at: FILES_TTL.from_now.to_i) }
|
render json: @template.schema_documents.map { |d| ActiveStorage::Blob.proxy_path(d.blob, expires_at: FILES_TTL.from_now.to_i) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ class TemplatesController < ApplicationController
|
|||||||
:name,
|
:name,
|
||||||
{ schema: [[:attachment_uuid, :google_drive_file_id, :name,
|
{ schema: [[:attachment_uuid, :google_drive_file_id, :name,
|
||||||
{ conditions: [%i[field_uuid value action operation]] }]],
|
{ conditions: [%i[field_uuid value action operation]] }]],
|
||||||
submitters: [%i[name uuid is_requester linked_to_uuid invite_by_uuid optional_invite_by_uuid email order]],
|
submitters: [%i[name uuid is_requester linked_to_uuid invite_via_field_uuid
|
||||||
|
invite_by_uuid optional_invite_by_uuid email order]],
|
||||||
fields: [[:uuid, :submitter_uuid, :name, :type,
|
fields: [[:uuid, :submitter_uuid, :name, :type,
|
||||||
:required, :readonly, :default_value,
|
:required, :readonly, :default_value,
|
||||||
:title, :description, :prefillable,
|
:title, :description, :prefillable,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class TemplatesRecipientsController < ApplicationController
|
|||||||
|
|
||||||
def submitters_params
|
def submitters_params
|
||||||
permit_params = { submitters: [%i[name uuid is_requester optional_invite_by_uuid
|
permit_params = { submitters: [%i[name uuid is_requester optional_invite_by_uuid
|
||||||
invite_by_uuid linked_to_uuid email option order]] }
|
invite_by_uuid invite_via_field_uuid linked_to_uuid email option order]] }
|
||||||
|
|
||||||
params.require(:template).permit(permit_params).fetch(:submitters, {}).values.filter_map do |s|
|
params.require(:template).permit(permit_params).fetch(:submitters, {}).values.filter_map do |s|
|
||||||
next if s[:uuid].blank?
|
next if s[:uuid].blank?
|
||||||
@@ -36,6 +36,7 @@ class TemplatesRecipientsController < ApplicationController
|
|||||||
s[:order] = s[:order].to_i if s[:order].present?
|
s[:order] = s[:order].to_i if s[:order].present?
|
||||||
s.delete(:invite_by_uuid) if s[:invite_by_uuid].blank?
|
s.delete(:invite_by_uuid) if s[:invite_by_uuid].blank?
|
||||||
s.delete(:optional_invite_by_uuid) if s[:optional_invite_by_uuid].blank?
|
s.delete(:optional_invite_by_uuid) if s[:optional_invite_by_uuid].blank?
|
||||||
|
s.delete(:invite_via_field_uuid) if s[:invite_via_field_uuid].blank?
|
||||||
|
|
||||||
normalize_option_value(s)
|
normalize_option_value(s)
|
||||||
end
|
end
|
||||||
@@ -53,6 +54,7 @@ class TemplatesRecipientsController < ApplicationController
|
|||||||
attrs.delete(:email)
|
attrs.delete(:email)
|
||||||
attrs.delete(:linked_to_uuid)
|
attrs.delete(:linked_to_uuid)
|
||||||
attrs.delete(:invite_by_uuid)
|
attrs.delete(:invite_by_uuid)
|
||||||
|
attrs.delete(:invite_via_field_uuid)
|
||||||
attrs.delete(:optional_invite_by_uuid)
|
attrs.delete(:optional_invite_by_uuid)
|
||||||
when /\Alinked_to_(.*)\z/
|
when /\Alinked_to_(.*)\z/
|
||||||
attrs[:linked_to_uuid] = ::Regexp.last_match(-1)
|
attrs[:linked_to_uuid] = ::Regexp.last_match(-1)
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import DashboardDropzone from './elements/dashboard_dropzone'
|
|||||||
import RequiredCheckboxGroup from './elements/required_checkbox_group'
|
import RequiredCheckboxGroup from './elements/required_checkbox_group'
|
||||||
import PageContainer from './elements/page_container'
|
import PageContainer from './elements/page_container'
|
||||||
import EmailEditor from './elements/email_editor'
|
import EmailEditor from './elements/email_editor'
|
||||||
|
import MarkdownEditor from './elements/markdown_editor'
|
||||||
import MountOnClick from './elements/mount_on_click'
|
import MountOnClick from './elements/mount_on_click'
|
||||||
import RemoveOnEvent from './elements/remove_on_event'
|
import RemoveOnEvent from './elements/remove_on_event'
|
||||||
import ScrollTo from './elements/scroll_to'
|
import ScrollTo from './elements/scroll_to'
|
||||||
@@ -131,6 +132,7 @@ safeRegisterElement('check-on-click', CheckOnClick)
|
|||||||
safeRegisterElement('required-checkbox-group', RequiredCheckboxGroup)
|
safeRegisterElement('required-checkbox-group', RequiredCheckboxGroup)
|
||||||
safeRegisterElement('page-container', PageContainer)
|
safeRegisterElement('page-container', PageContainer)
|
||||||
safeRegisterElement('email-editor', EmailEditor)
|
safeRegisterElement('email-editor', EmailEditor)
|
||||||
|
safeRegisterElement('markdown-editor', MarkdownEditor)
|
||||||
safeRegisterElement('mount-on-click', MountOnClick)
|
safeRegisterElement('mount-on-click', MountOnClick)
|
||||||
safeRegisterElement('remove-on-event', RemoveOnEvent)
|
safeRegisterElement('remove-on-event', RemoveOnEvent)
|
||||||
safeRegisterElement('scroll-to', ScrollTo)
|
safeRegisterElement('scroll-to', ScrollTo)
|
||||||
|
|||||||
@@ -155,3 +155,7 @@ button[disabled] .enabled, button.btn-disabled .enabled {
|
|||||||
.font-courier {
|
.font-courier {
|
||||||
font-family: "Courier New", Consolas, "Liberation Mono", monospace, ui-monospace, SFMono-Regular, Menlo, Monaco;
|
font-family: "Courier New", Consolas, "Liberation Mono", monospace, ui-monospace, SFMono-Regular, Menlo, Monaco;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markdown-editor [contenteditable] p {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,385 @@
|
|||||||
|
import { target, targetable } from '@github/catalyst/lib/targetable'
|
||||||
|
import { actionable } from '@github/catalyst/lib/actionable'
|
||||||
|
|
||||||
|
function loadTiptap () {
|
||||||
|
return Promise.all([
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/core'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extension-bold'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extension-italic'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extension-paragraph'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extension-text'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extension-hard-break'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extension-document'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extension-link'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extension-underline'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/extensions'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/markdown'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/pm/state'),
|
||||||
|
import(/* webpackChunkName: "markdown-editor" */ '@tiptap/pm/view')
|
||||||
|
]).then(([core, bold, italic, paragraph, text, hardBreak, document, link, underline, extensions, markdown, pmState, pmView]) => ({
|
||||||
|
Editor: core.Editor,
|
||||||
|
Extension: core.Extension,
|
||||||
|
Bold: bold.default || bold,
|
||||||
|
Italic: italic.default || italic,
|
||||||
|
Paragraph: paragraph.default || paragraph,
|
||||||
|
Text: text.default || text,
|
||||||
|
HardBreak: hardBreak.default || hardBreak,
|
||||||
|
Document: document.default || document,
|
||||||
|
Link: link.default || link,
|
||||||
|
Underline: underline.default || underline,
|
||||||
|
UndoRedo: extensions.UndoRedo,
|
||||||
|
Markdown: markdown.Markdown,
|
||||||
|
Plugin: pmState.Plugin,
|
||||||
|
Decoration: pmView.Decoration,
|
||||||
|
DecorationSet: pmView.DecorationSet
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinkTooltip {
|
||||||
|
constructor (container, editor) {
|
||||||
|
this.container = container
|
||||||
|
this.editor = editor
|
||||||
|
|
||||||
|
const template = document.createElement('template')
|
||||||
|
|
||||||
|
template.innerHTML = container.dataset.linkTooltipHtml
|
||||||
|
|
||||||
|
this.tooltip = template.content.firstElementChild
|
||||||
|
|
||||||
|
this.input = this.tooltip.querySelector('input')
|
||||||
|
this.saveButton = this.tooltip.querySelector('[data-role="link-save"]')
|
||||||
|
this.removeButton = this.tooltip.querySelector('[data-role="link-remove"]')
|
||||||
|
|
||||||
|
container.style.position = 'relative'
|
||||||
|
container.appendChild(this.tooltip)
|
||||||
|
}
|
||||||
|
|
||||||
|
isVisible () {
|
||||||
|
return !this.tooltip.classList.contains('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizeUrl (url) {
|
||||||
|
if (!url) return url
|
||||||
|
if (/^{/i.test(url)) return url
|
||||||
|
if (/^https?:\/\//i.test(url)) return url
|
||||||
|
if (/^mailto:/i.test(url)) return url
|
||||||
|
|
||||||
|
return `https://${url}`
|
||||||
|
}
|
||||||
|
|
||||||
|
show (url, pos, { focus = false } = {}) {
|
||||||
|
this.input.value = url || ''
|
||||||
|
this.removeButton.classList.toggle('hidden', !url)
|
||||||
|
|
||||||
|
this.tooltip.classList.remove('hidden')
|
||||||
|
|
||||||
|
const coords = this.editor.view.coordsAtPos(pos)
|
||||||
|
const containerRect = this.container.getBoundingClientRect()
|
||||||
|
|
||||||
|
this.tooltip.style.left = `${coords.left - containerRect.left}px`
|
||||||
|
this.tooltip.style.top = `${coords.bottom - containerRect.top + 4}px`
|
||||||
|
|
||||||
|
if (focus) this.input.focus()
|
||||||
|
|
||||||
|
this.saveHandler = () => {
|
||||||
|
const inputUrl = this.input.value.trim()
|
||||||
|
|
||||||
|
if (inputUrl) {
|
||||||
|
this.editor.chain().focus().extendMarkRange('link').setLink({ href: this.normalizeUrl(inputUrl) }).run()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeHandler = () => {
|
||||||
|
this.editor.chain().focus().extendMarkRange('link').unsetLink().run()
|
||||||
|
|
||||||
|
this.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keyHandler = (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault()
|
||||||
|
this.saveHandler()
|
||||||
|
} else if (e.key === 'Escape') {
|
||||||
|
e.preventDefault()
|
||||||
|
this.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveButton.addEventListener('click', this.saveHandler, { once: true })
|
||||||
|
this.removeButton.addEventListener('click', this.removeHandler, { once: true })
|
||||||
|
this.input.addEventListener('keydown', this.keyHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
hide () {
|
||||||
|
if (this.saveHandler) {
|
||||||
|
this.saveButton.removeEventListener('click', this.saveHandler)
|
||||||
|
this.saveHandler = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.removeHandler) {
|
||||||
|
this.removeButton.removeEventListener('click', this.removeHandler)
|
||||||
|
this.removeHandler = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.keyHandler) {
|
||||||
|
this.input.removeEventListener('keydown', this.keyHandler)
|
||||||
|
this.keyHandler = null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tooltip.classList.add('hidden')
|
||||||
|
this.currentMark = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default actionable(targetable(class extends HTMLElement {
|
||||||
|
static [target.static] = [
|
||||||
|
'textarea',
|
||||||
|
'editorElement',
|
||||||
|
'boldButton',
|
||||||
|
'italicButton',
|
||||||
|
'underlineButton',
|
||||||
|
'linkButton'
|
||||||
|
]
|
||||||
|
|
||||||
|
async connectedCallback () {
|
||||||
|
if (!this.textarea || !this.editorElement) return
|
||||||
|
|
||||||
|
this.textarea.style.display = 'none'
|
||||||
|
this.adjustShortcutsForPlatform()
|
||||||
|
|
||||||
|
const { Editor, Extension, Bold, Italic, Paragraph, Text, HardBreak, UndoRedo, Document, Link, Underline, Markdown, Plugin, Decoration, DecorationSet } = await loadTiptap()
|
||||||
|
|
||||||
|
const buildDecorations = (doc) => {
|
||||||
|
const decorations = []
|
||||||
|
const regex = /\{\{?[a-zA-Z0-9_.-]+\}\}?/g
|
||||||
|
|
||||||
|
doc.descendants((node, pos) => {
|
||||||
|
if (!node.isText) return
|
||||||
|
|
||||||
|
let match
|
||||||
|
|
||||||
|
while ((match = regex.exec(node.text)) !== null) {
|
||||||
|
decorations.push(
|
||||||
|
Decoration.inline(pos + match.index, pos + match.index + match[0].length, {
|
||||||
|
class: 'bg-amber-100 py-0.5 px-1 rounded'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return DecorationSet.create(doc, decorations)
|
||||||
|
}
|
||||||
|
|
||||||
|
const VariableHighlight = Extension.create({
|
||||||
|
name: 'variableHighlight',
|
||||||
|
addProseMirrorPlugins () {
|
||||||
|
return [new Plugin({
|
||||||
|
state: {
|
||||||
|
init (_, { doc }) {
|
||||||
|
return buildDecorations(doc)
|
||||||
|
},
|
||||||
|
apply (tr, oldSet) {
|
||||||
|
return tr.docChanged ? buildDecorations(tr.doc) : oldSet
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
decorations (state) {
|
||||||
|
return this.getState(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.editor = new Editor({
|
||||||
|
element: this.editorElement,
|
||||||
|
extensions: [
|
||||||
|
Markdown,
|
||||||
|
Document,
|
||||||
|
Paragraph,
|
||||||
|
Text,
|
||||||
|
Bold,
|
||||||
|
Italic,
|
||||||
|
HardBreak.extend({
|
||||||
|
addKeyboardShortcuts () {
|
||||||
|
return {
|
||||||
|
Enter: () => this.editor.commands.setHardBreak()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UndoRedo,
|
||||||
|
Link.extend({
|
||||||
|
inclusive: true,
|
||||||
|
addKeyboardShortcuts: () => ({
|
||||||
|
'Mod-k': () => {
|
||||||
|
this.toggleLink()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).configure({
|
||||||
|
openOnClick: false,
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: 'link',
|
||||||
|
'data-turbo': 'false',
|
||||||
|
style: 'color: #2563eb; text-decoration: underline; cursor: text;'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Underline,
|
||||||
|
VariableHighlight
|
||||||
|
],
|
||||||
|
content: (this.textarea.value || '').trim().replace(/ *\n/g, '<br>'),
|
||||||
|
contentType: 'markdown',
|
||||||
|
editorProps: {
|
||||||
|
attributes: {
|
||||||
|
style: 'min-height: 220px',
|
||||||
|
dir: 'auto',
|
||||||
|
class: 'p-3 outline-none focus:outline-none'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onUpdate: ({ editor }) => {
|
||||||
|
this.textarea.value = editor.getMarkdown()
|
||||||
|
this.textarea.dispatchEvent(new Event('input', { bubbles: true }))
|
||||||
|
},
|
||||||
|
onSelectionUpdate: ({ editor }) => {
|
||||||
|
this.updateToolbarState()
|
||||||
|
this.handleLinkTooltip(editor)
|
||||||
|
},
|
||||||
|
onBlur: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.linkTooltip.tooltip.contains(document.activeElement)) {
|
||||||
|
this.linkTooltip.hide()
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.linkTooltip = new LinkTooltip(this, this.editor)
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustShortcutsForPlatform () {
|
||||||
|
if ((navigator.userAgentData?.platform || navigator.platform)?.toLowerCase()?.includes('mac')) {
|
||||||
|
this.querySelectorAll('.tooltip[data-tip]').forEach(tooltip => {
|
||||||
|
const tip = tooltip.getAttribute('data-tip')
|
||||||
|
|
||||||
|
if (tip && tip.includes('Ctrl')) {
|
||||||
|
tooltip.setAttribute('data-tip', tip.replace(/Ctrl/g, '⌘'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bold (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.editor.chain().focus().toggleBold().run()
|
||||||
|
this.updateToolbarState()
|
||||||
|
}
|
||||||
|
|
||||||
|
italic (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.editor.chain().focus().toggleItalic().run()
|
||||||
|
this.updateToolbarState()
|
||||||
|
}
|
||||||
|
|
||||||
|
underline (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.editor.chain().focus().toggleUnderline().run()
|
||||||
|
this.updateToolbarState()
|
||||||
|
}
|
||||||
|
|
||||||
|
linkSelection (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.toggleLink()
|
||||||
|
this.updateToolbarState()
|
||||||
|
}
|
||||||
|
|
||||||
|
undo (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.editor.chain().focus().undo().run()
|
||||||
|
this.updateToolbarState()
|
||||||
|
}
|
||||||
|
|
||||||
|
redo (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.editor.chain().focus().redo().run()
|
||||||
|
this.updateToolbarState()
|
||||||
|
}
|
||||||
|
|
||||||
|
updateToolbarState () {
|
||||||
|
this.boldButton.classList.toggle('bg-base-200', this.editor.isActive('bold'))
|
||||||
|
this.italicButton.classList.toggle('bg-base-200', this.editor.isActive('italic'))
|
||||||
|
this.underlineButton.classList.toggle('bg-base-200', this.editor.isActive('underline'))
|
||||||
|
this.linkButton.classList.toggle('bg-base-200', this.editor.isActive('link'))
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLinkTooltip (editor) {
|
||||||
|
const { from } = editor.state.selection
|
||||||
|
const mark = editor.state.doc.resolve(from).marks().find(m => m.type.name === 'link')
|
||||||
|
|
||||||
|
if (!mark) {
|
||||||
|
if (this.linkTooltip.isVisible()) this.linkTooltip.hide()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.linkTooltip.isVisible() && this.linkTooltip.currentMark === mark) return
|
||||||
|
|
||||||
|
let linkStart = from
|
||||||
|
const start = editor.state.doc.resolve(from).start()
|
||||||
|
|
||||||
|
for (let i = from - 1; i >= start; i--) {
|
||||||
|
if (editor.state.doc.resolve(i).marks().some(m => m.eq(mark))) {
|
||||||
|
linkStart = i
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.linkTooltip.hide()
|
||||||
|
this.linkTooltip.show(mark.attrs.href, linkStart > start ? linkStart - 1 : linkStart)
|
||||||
|
this.linkTooltip.currentMark = mark
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleLink () {
|
||||||
|
if (this.editor.isActive('link')) {
|
||||||
|
this.linkTooltip.hide()
|
||||||
|
this.editor.chain().focus().extendMarkRange('link').unsetLink().run()
|
||||||
|
this.updateToolbarState()
|
||||||
|
} else {
|
||||||
|
const { from } = this.editor.state.selection
|
||||||
|
|
||||||
|
this.linkTooltip.hide()
|
||||||
|
this.linkTooltip.show(this.editor.getAttributes('link').href, from, { focus: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insertVariable (e) {
|
||||||
|
const variable = e.target.closest('[data-variable]')?.dataset.variable
|
||||||
|
|
||||||
|
if (variable) {
|
||||||
|
const { from, to } = this.editor.state.selection
|
||||||
|
|
||||||
|
if (variable.includes('link') && from !== to) {
|
||||||
|
this.editor.chain().focus().setLink({ href: `{${variable}}` }).run()
|
||||||
|
} else {
|
||||||
|
this.editor.chain().focus().insertContent(`{${variable}}`).run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback () {
|
||||||
|
this.linkTooltip.hide()
|
||||||
|
|
||||||
|
if (this.editor) {
|
||||||
|
this.editor.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
export default class extends HTMLElement {
|
export default class extends HTMLElement {
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
this.input.addEventListener('change', (event) => {
|
this.input.addEventListener('change', (event) => {
|
||||||
|
if (!this.target) return
|
||||||
|
|
||||||
|
const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value
|
||||||
|
const dataValue = this.dataset.value === 'false' ? false : this.dataset.value || true
|
||||||
|
|
||||||
if (this.dataset.attribute) {
|
if (this.dataset.attribute) {
|
||||||
this.target[this.dataset.attribute] = event.target.checked
|
this.target[this.dataset.attribute] = value === dataValue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.dataset.className) {
|
if (this.dataset.className) {
|
||||||
this.target.classList.toggle(this.dataset.className, event.target.value !== this.dataset.value)
|
this.target.classList.toggle(this.dataset.className, value !== dataValue)
|
||||||
|
|
||||||
if (this.dataset.className === 'hidden' && this.target.tagName === 'INPUT') {
|
if (this.dataset.className === 'hidden' && this.target.tagName === 'INPUT') {
|
||||||
this.target.disabled = event.target.value !== this.dataset.value
|
this.target.disabled = event.target.value !== this.dataset.value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
export default class extends HTMLElement {
|
export default class extends HTMLElement {
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
const button = this.querySelector('a, button')
|
const button = this.querySelector('a, button, label')
|
||||||
|
|
||||||
|
const target = this.dataset.targetId ? document.getElementById(this.dataset.targetId) : button
|
||||||
|
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
this.dataset.classes.split(' ').forEach((cls) => {
|
this.dataset.classes.split(' ').forEach((cls) => {
|
||||||
button.classList.toggle(cls)
|
if (this.dataset.action === 'remove') {
|
||||||
|
target.classList.remove(cls)
|
||||||
|
} else if (this.dataset.action === 'add') {
|
||||||
|
target.classList.add(cls)
|
||||||
|
} else {
|
||||||
|
target.classList.toggle(cls)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const en = {
|
const en = {
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Please upload an image file',
|
please_upload_an_image_file: 'Please upload an image file',
|
||||||
must_be_characters_length: 'Must be {number} characters length',
|
must_be_characters_length: 'Must be {number} characters long',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'Complete all required fields to proceed with identity verification.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Complete all required fields to proceed with identity verification.',
|
||||||
verify_id: 'Verify ID',
|
verify_id: 'Verify ID',
|
||||||
identity_verification: 'Identity verification',
|
identity_verification: 'Identity verification',
|
||||||
@@ -97,6 +97,7 @@ const en = {
|
|||||||
upload: 'Upload',
|
upload: 'Upload',
|
||||||
files: 'Files',
|
files: 'Files',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'Signature is too small or simple. Please redraw.',
|
signature_is_too_small_or_simple_please_redraw: 'Signature is too small or simple. Please redraw.',
|
||||||
|
browser_privacy_settings_block_canvas: 'Your browser privacy settings restrict use of the drawing canvas. Please use a different browser or device, or disable privacy settings that block canvas in order to sign.',
|
||||||
wait_countdown_seconds: 'Wait {countdown} seconds'
|
wait_countdown_seconds: 'Wait {countdown} seconds'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +200,7 @@ const es = {
|
|||||||
upload: 'Subir',
|
upload: 'Subir',
|
||||||
files: 'Archivos',
|
files: 'Archivos',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'La firma es demasiado pequeña o simple. Por favor, vuelve a dibujarla.',
|
signature_is_too_small_or_simple_please_redraw: 'La firma es demasiado pequeña o simple. Por favor, vuelve a dibujarla.',
|
||||||
|
browser_privacy_settings_block_canvas: 'La configuración de privacidad de su navegador restringe el uso del lienzo de dibujo. Utilice un navegador o dispositivo diferente, o desactive la configuración de privacidad que bloquea el lienzo para firmar.',
|
||||||
wait_countdown_seconds: 'Espera {countdown} segundos'
|
wait_countdown_seconds: 'Espera {countdown} segundos'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,6 +303,7 @@ const it = {
|
|||||||
upload: 'Carica',
|
upload: 'Carica',
|
||||||
files: 'File',
|
files: 'File',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'La firma è troppo piccola o semplice. Ridisegnala, per favore.',
|
signature_is_too_small_or_simple_please_redraw: 'La firma è troppo piccola o semplice. Ridisegnala, per favore.',
|
||||||
|
browser_privacy_settings_block_canvas: 'Le impostazioni sulla privacy del browser limitano l\'uso dell\'area di disegno. Utilizza un browser o dispositivo diverso oppure disattiva le impostazioni sulla privacy che bloccano il canvas per firmare.',
|
||||||
wait_countdown_seconds: 'Attendi {countdown} secondi'
|
wait_countdown_seconds: 'Attendi {countdown} secondi'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,6 +406,7 @@ const de = {
|
|||||||
upload: 'Hochladen',
|
upload: 'Hochladen',
|
||||||
files: 'Dateien',
|
files: 'Dateien',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'Die Unterschrift ist zu klein oder zu einfach. Bitte neu zeichnen.',
|
signature_is_too_small_or_simple_please_redraw: 'Die Unterschrift ist zu klein oder zu einfach. Bitte neu zeichnen.',
|
||||||
|
browser_privacy_settings_block_canvas: 'Die Datenschutzeinstellungen Ihres Browsers schränken die Nutzung der Zeichenfläche ein. Bitte verwenden Sie einen anderen Browser oder ein anderes Gerät oder deaktivieren Sie die Datenschutzeinstellungen, die Canvas blockieren, um zu unterschreiben.',
|
||||||
wait_countdown_seconds: 'Bitte {countdown} Sekunden warten'
|
wait_countdown_seconds: 'Bitte {countdown} Sekunden warten'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,6 +509,7 @@ const fr = {
|
|||||||
upload: 'Téléverser',
|
upload: 'Téléverser',
|
||||||
files: 'Fichiers',
|
files: 'Fichiers',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'La signature est trop petite ou trop simple. Veuillez la redessiner.',
|
signature_is_too_small_or_simple_please_redraw: 'La signature est trop petite ou trop simple. Veuillez la redessiner.',
|
||||||
|
browser_privacy_settings_block_canvas: 'Les paramètres de confidentialité de votre navigateur empêchent l\'utilisation du canevas de dessin. Veuillez utiliser un autre navigateur ou appareil, ou désactiver les paramètres de confidentialité qui bloquent le canevas pour signer.',
|
||||||
wait_countdown_seconds: 'Veuillez patienter {countdown} secondes'
|
wait_countdown_seconds: 'Veuillez patienter {countdown} secondes'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,6 +612,7 @@ const pl = {
|
|||||||
upload: 'Przesyłanie',
|
upload: 'Przesyłanie',
|
||||||
files: 'Pliki',
|
files: 'Pliki',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'Podpis jest zbyt mały lub zbyt prosty. Proszę narysować go ponownie.',
|
signature_is_too_small_or_simple_please_redraw: 'Podpis jest zbyt mały lub zbyt prosty. Proszę narysować go ponownie.',
|
||||||
|
browser_privacy_settings_block_canvas: 'Ustawienia prywatności przeglądarki blokują użycie obszaru rysowania. Użyj innej przeglądarki lub urządzenia albo wyłącz ustawienia prywatności blokujące canvas, aby podpisać.',
|
||||||
wait_countdown_seconds: 'Poczekaj {countdown} sekund'
|
wait_countdown_seconds: 'Poczekaj {countdown} sekund'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,6 +715,7 @@ const uk = {
|
|||||||
upload: 'Завантажити',
|
upload: 'Завантажити',
|
||||||
files: 'Файли',
|
files: 'Файли',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'Підпис занадто маленький або надто простий. Будь ласка, перемалюйте.',
|
signature_is_too_small_or_simple_please_redraw: 'Підпис занадто маленький або надто простий. Будь ласка, перемалюйте.',
|
||||||
|
browser_privacy_settings_block_canvas: 'Налаштування конфіденційності вашого браузера блокують використання полотна для малювання. Будь ласка, скористайтеся іншим браузером або пристроєм, або вимкніть налаштування конфіденційності, що блокують canvas, щоб підписати.',
|
||||||
wait_countdown_seconds: 'Зачекайте {countdown} секунд'
|
wait_countdown_seconds: 'Зачекайте {countdown} секунд'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,6 +818,7 @@ const cs = {
|
|||||||
upload: 'Nahrát',
|
upload: 'Nahrát',
|
||||||
files: 'Soubory',
|
files: 'Soubory',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'Podpis je příliš malý nebo jednoduchý. Nakreslete jej prosím znovu.',
|
signature_is_too_small_or_simple_please_redraw: 'Podpis je příliš malý nebo jednoduchý. Nakreslete jej prosím znovu.',
|
||||||
|
browser_privacy_settings_block_canvas: 'Nastavení soukromí vašeho prohlížeče omezuje použití kreslicího plátna. Použijte prosím jiný prohlížeč nebo zařízení, nebo vypněte nastavení soukromí blokující canvas pro podepsání.',
|
||||||
wait_countdown_seconds: 'Počkejte {countdown} sekund'
|
wait_countdown_seconds: 'Počkejte {countdown} sekund'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,6 +921,7 @@ const pt = {
|
|||||||
upload: 'Carregar',
|
upload: 'Carregar',
|
||||||
files: 'Arquivos',
|
files: 'Arquivos',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'A assinatura é muito pequena ou simples. Por favor, redesenhe.',
|
signature_is_too_small_or_simple_please_redraw: 'A assinatura é muito pequena ou simples. Por favor, redesenhe.',
|
||||||
|
browser_privacy_settings_block_canvas: 'As configurações de privacidade do seu navegador restringem o uso da área de desenho. Use um navegador ou dispositivo diferente, ou desative as configurações de privacidade que bloqueiam o canvas para assinar.',
|
||||||
wait_countdown_seconds: 'Aguarde {countdown} segundos'
|
wait_countdown_seconds: 'Aguarde {countdown} segundos'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1015,6 +1024,7 @@ const he = {
|
|||||||
upload: 'העלאה',
|
upload: 'העלאה',
|
||||||
files: 'קבצים',
|
files: 'קבצים',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'החתימה קטנה או פשוטה מדי. אנא חתום מחדש.',
|
signature_is_too_small_or_simple_please_redraw: 'החתימה קטנה או פשוטה מדי. אנא חתום מחדש.',
|
||||||
|
browser_privacy_settings_block_canvas: 'הגדרות הפרטיות של הדפדפן שלך מגבילות את השימוש באזור הציור. אנא השתמש בדפדפן או מכשיר אחר, או בטל את הגדרות הפרטיות החוסמות canvas כדי לחתום.',
|
||||||
wait_countdown_seconds: 'המתן {countdown} שניות'
|
wait_countdown_seconds: 'המתן {countdown} שניות'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1117,6 +1127,7 @@ const nl = {
|
|||||||
upload: 'Uploaden',
|
upload: 'Uploaden',
|
||||||
files: 'Bestanden',
|
files: 'Bestanden',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'De handtekening is te klein of te eenvoudig. Teken opnieuw.',
|
signature_is_too_small_or_simple_please_redraw: 'De handtekening is te klein of te eenvoudig. Teken opnieuw.',
|
||||||
|
browser_privacy_settings_block_canvas: 'De privacyinstellingen van uw browser beperken het gebruik van het tekenveld. Gebruik een andere browser of ander apparaat, of schakel de privacyinstellingen uit die canvas blokkeren om te ondertekenen.',
|
||||||
wait_countdown_seconds: 'Wacht {countdown} seconden'
|
wait_countdown_seconds: 'Wacht {countdown} seconden'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1219,6 +1230,7 @@ const ar = {
|
|||||||
upload: 'تحميل',
|
upload: 'تحميل',
|
||||||
files: 'الملفات',
|
files: 'الملفات',
|
||||||
signature_is_too_small_or_simple_please_redraw: 'التوقيع صغير جدًا أو بسيط جدًا. يرجى إعادة رسمه.',
|
signature_is_too_small_or_simple_please_redraw: 'التوقيع صغير جدًا أو بسيط جدًا. يرجى إعادة رسمه.',
|
||||||
|
browser_privacy_settings_block_canvas: 'إعدادات الخصوصية في متصفحك تمنع استخدام لوحة الرسم. يرجى استخدام متصفح أو جهاز مختلف، أو تعطيل إعدادات الخصوصية التي تحظر canvas للتوقيع.',
|
||||||
wait_countdown_seconds: 'انتظر {countdown} ثانية'
|
wait_countdown_seconds: 'انتظر {countdown} ثانية'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1321,6 +1333,7 @@ const ko = {
|
|||||||
upload: '업로드',
|
upload: '업로드',
|
||||||
files: '파일',
|
files: '파일',
|
||||||
signature_is_too_small_or_simple_please_redraw: '서명이 너무 작거나 단순합니다. 다시 그려주세요.',
|
signature_is_too_small_or_simple_please_redraw: '서명이 너무 작거나 단순합니다. 다시 그려주세요.',
|
||||||
|
browser_privacy_settings_block_canvas: '브라우저 개인정보 보호 설정으로 인해 그리기 캔버스를 사용할 수 없습니다. 다른 브라우저나 기기를 사용하거나, 서명을 위해 캔버스를 차단하는 개인정보 보호 설정을 비활성화해 주세요.',
|
||||||
wait_countdown_seconds: '{countdown}초 기다리세요'
|
wait_countdown_seconds: '{countdown}초 기다리세요'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1423,6 +1436,7 @@ const ja = {
|
|||||||
upload: 'アップロード',
|
upload: 'アップロード',
|
||||||
files: 'ファイル',
|
files: 'ファイル',
|
||||||
signature_is_too_small_or_simple_please_redraw: '署名が小さすぎるか単純すぎます。もう一度描いてください。',
|
signature_is_too_small_or_simple_please_redraw: '署名が小さすぎるか単純すぎます。もう一度描いてください。',
|
||||||
|
browser_privacy_settings_block_canvas: 'ブラウザのプライバシー設定により、描画キャンバスの使用が制限されています。別のブラウザまたはデバイスを使用するか、署名するためにキャンバスをブロックするプライバシー設定を無効にしてください。',
|
||||||
wait_countdown_seconds: '{countdown} 秒お待ちください'
|
wait_countdown_seconds: '{countdown} 秒お待ちください'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -150,6 +150,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { cropCanvasAndExportToPNG } from './crop_canvas'
|
import { cropCanvasAndExportToPNG } from './crop_canvas'
|
||||||
|
import { isCanvasBlocked } from './validate_signature'
|
||||||
import { IconReload, IconTextSize, IconUpload, IconSignature, IconArrowsDiagonalMinimize2 } from '@tabler/icons-vue'
|
import { IconReload, IconTextSize, IconUpload, IconSignature, IconArrowsDiagonalMinimize2 } from '@tabler/icons-vue'
|
||||||
import SignaturePad from 'signature_pad'
|
import SignaturePad from 'signature_pad'
|
||||||
import AppearsOn from './appears_on'
|
import AppearsOn from './appears_on'
|
||||||
@@ -419,7 +420,15 @@ export default {
|
|||||||
}
|
}
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
if (this.field.required === true) {
|
if (this.field.required === true) {
|
||||||
alert(this.t('signature_is_too_small_or_simple_please_redraw'))
|
if (isCanvasBlocked()) {
|
||||||
|
alert(this.t('browser_privacy_settings_block_canvas'))
|
||||||
|
|
||||||
|
if (window.Rollbar) {
|
||||||
|
window.Rollbar.info('Canvas blocked')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(this.t('signature_is_too_small_or_simple_please_redraw'))
|
||||||
|
}
|
||||||
|
|
||||||
return reject(error)
|
return reject(error)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -309,7 +309,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { IconReload, IconCamera, IconSignature, IconTextSize, IconArrowsDiagonalMinimize2, IconQrcode, IconX } from '@tabler/icons-vue'
|
import { IconReload, IconCamera, IconSignature, IconTextSize, IconArrowsDiagonalMinimize2, IconQrcode, IconX } from '@tabler/icons-vue'
|
||||||
import { cropCanvasAndExportToPNG } from './crop_canvas'
|
import { cropCanvasAndExportToPNG } from './crop_canvas'
|
||||||
import { isValidSignatureCanvas } from './validate_signature'
|
import { isValidSignatureCanvas, isCanvasBlocked } from './validate_signature'
|
||||||
import SignaturePad from 'signature_pad'
|
import SignaturePad from 'signature_pad'
|
||||||
import AppearsOn from './appears_on'
|
import AppearsOn from './appears_on'
|
||||||
import FileDropzone from './dropzone'
|
import FileDropzone from './dropzone'
|
||||||
@@ -790,7 +790,15 @@ export default {
|
|||||||
|
|
||||||
if (this.isSignatureStarted && this.pad.toData().length > 0 && !isValidSignatureCanvas(this.pad.toData())) {
|
if (this.isSignatureStarted && this.pad.toData().length > 0 && !isValidSignatureCanvas(this.pad.toData())) {
|
||||||
if (this.field.required === true || this.pad.toData().length > 0) {
|
if (this.field.required === true || this.pad.toData().length > 0) {
|
||||||
alert(this.t('signature_is_too_small_or_simple_please_redraw'))
|
if (isCanvasBlocked()) {
|
||||||
|
alert(this.t('browser_privacy_settings_block_canvas'))
|
||||||
|
|
||||||
|
if (window.Rollbar) {
|
||||||
|
window.Rollbar.info('Canvas blocked')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(this.t('signature_is_too_small_or_simple_please_redraw'))
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.reject(new Error('Image too small or simple'))
|
return Promise.reject(new Error('Image too small or simple'))
|
||||||
} else {
|
} else {
|
||||||
@@ -846,7 +854,15 @@ export default {
|
|||||||
}
|
}
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
if (this.field.required === true) {
|
if (this.field.required === true) {
|
||||||
alert(this.t('signature_is_too_small_or_simple_please_redraw'))
|
if (isCanvasBlocked()) {
|
||||||
|
alert(this.t('browser_privacy_settings_block_canvas'))
|
||||||
|
|
||||||
|
if (window.Rollbar) {
|
||||||
|
window.Rollbar.info('Canvas blocked')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(this.t('signature_is_too_small_or_simple_please_redraw'))
|
||||||
|
}
|
||||||
|
|
||||||
return reject(error)
|
return reject(error)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -35,4 +35,24 @@ function isValidSignatureCanvas (data) {
|
|||||||
return validStrokes.length > 0
|
return validStrokes.length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
export { isValidSignatureCanvas }
|
function isCanvasBlocked () {
|
||||||
|
try {
|
||||||
|
const testCanvas = document.createElement('canvas')
|
||||||
|
|
||||||
|
testCanvas.width = 2
|
||||||
|
testCanvas.height = 2
|
||||||
|
|
||||||
|
const ctx = testCanvas.getContext('2d')
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgb(255, 0, 0)'
|
||||||
|
ctx.fillRect(0, 0, 2, 2)
|
||||||
|
|
||||||
|
const pixel = ctx.getImageData(0, 0, 1, 1).data
|
||||||
|
|
||||||
|
return pixel[0] !== 255 || pixel[1] !== 0 || pixel[2] !== 0 || pixel[3] !== 255
|
||||||
|
} catch (e) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { isValidSignatureCanvas, isCanvasBlocked }
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
/>
|
/>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<form
|
<form
|
||||||
v-if="withSignYourselfButton && template.submitters.length < 2"
|
v-if="withSignYourselfButton && undefinedSubmitters.length < 2"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
data-turbo="false"
|
data-turbo="false"
|
||||||
class="inline"
|
class="inline"
|
||||||
@@ -938,6 +938,16 @@ export default {
|
|||||||
language () {
|
language () {
|
||||||
return this.locale.split('-')[0].toLowerCase()
|
return this.locale.split('-')[0].toLowerCase()
|
||||||
},
|
},
|
||||||
|
undefinedSubmitters () {
|
||||||
|
return this.template.submitters.filter((submitter) => {
|
||||||
|
return !submitter.invite_by_uuid &&
|
||||||
|
!submitter.optional_invite_by_uuid &&
|
||||||
|
!submitter.invite_via_field_uuid &&
|
||||||
|
!submitter.linked_to_uuid &&
|
||||||
|
!submitter.is_requester &&
|
||||||
|
!submitter.email
|
||||||
|
})
|
||||||
|
},
|
||||||
withPrefillable () {
|
withPrefillable () {
|
||||||
if (this.template.fields) {
|
if (this.template.fields) {
|
||||||
return this.template.fields.some((f) => f.prefillable)
|
return this.template.fields.some((f) => f.prefillable)
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
fields () {
|
fields () {
|
||||||
return this.template.fields.reduce((acc, f) => {
|
return this.template.fields.reduce((acc, f) => {
|
||||||
if (f !== this.field && ['number'].includes(f.type) && (!f.preferences?.formula || !f.preferences.formula.includes(this.field.uuid))) {
|
if (f !== this.field && this.isNumberField(f) && (!f.preferences?.formula || !f.preferences.formula.includes(this.field.uuid))) {
|
||||||
acc.push(f)
|
acc.push(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,9 +176,12 @@ export default {
|
|||||||
this.formula = this.humanizeFormula(this.field.preferences.formula || '')
|
this.formula = this.humanizeFormula(this.field.preferences.formula || '')
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
isNumberField (field) {
|
||||||
|
return field.type === 'number' || (['radio', 'select'].includes(field.type) && field.options?.every((o) => String(o.value).match(/^[\d.-]+$/)))
|
||||||
|
},
|
||||||
humanizeFormula (text) {
|
humanizeFormula (text) {
|
||||||
return text.replace(/{{(.*?)}}/g, (match, uuid) => {
|
return text.replace(/{{(.*?)}}/g, (match, uuid) => {
|
||||||
const foundField = this.fields.find((f) => f.uuid === uuid)
|
const foundField = this.template.fields.find((f) => f.uuid === uuid)
|
||||||
|
|
||||||
if (foundField) {
|
if (foundField) {
|
||||||
return `{{${foundField.name || this.buildDefaultName(foundField)}}}`
|
return `{{${foundField.name || this.buildDefaultName(foundField)}}}`
|
||||||
@@ -189,7 +192,7 @@ export default {
|
|||||||
},
|
},
|
||||||
normalizeFormula (text) {
|
normalizeFormula (text) {
|
||||||
return text.replace(/{{(.*?)}}/g, (match, name) => {
|
return text.replace(/{{(.*?)}}/g, (match, name) => {
|
||||||
const foundField = this.fields.find((f) => {
|
const foundField = this.template.fields.find((f) => {
|
||||||
return (f.name || this.buildDefaultName(f)).trim() === name.trim()
|
return (f.name || this.buildDefaultName(f)).trim() === name.trim()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ const en = {
|
|||||||
learn_more: 'Learn more',
|
learn_more: 'Learn more',
|
||||||
and: 'and',
|
and: 'and',
|
||||||
or: 'or',
|
or: 'or',
|
||||||
start_a_quick_tour_to_learn_how_to_create_an_send_your_first_document: 'Start a quick tour to learn how to create an send your first document',
|
start_a_quick_tour_to_learn_how_to_create_an_send_your_first_document: 'Start a quick tour to learn how to create and send your first document',
|
||||||
start_tour: 'Start Tour',
|
start_tour: 'Start Tour',
|
||||||
or_add_from: 'Or add from',
|
or_add_from: 'Or add from',
|
||||||
sync: 'Sync',
|
sync: 'Sync',
|
||||||
|
|||||||
@@ -14,12 +14,7 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
@email_message = submitter.account.email_messages.find_by(uuid: submitter.preferences['email_message_uuid'])
|
@email_message = submitter.account.email_messages.find_by(uuid: submitter.preferences['email_message_uuid'])
|
||||||
end
|
end
|
||||||
|
|
||||||
template_submitters_index =
|
template_submitters_index = @email_message.blank? ? build_submitter_preferences_index(@submitter) : {}
|
||||||
if @email_message.blank?
|
|
||||||
build_submitter_preferences_index(@submitter)
|
|
||||||
else
|
|
||||||
{}
|
|
||||||
end
|
|
||||||
|
|
||||||
@body = @email_message&.body.presence ||
|
@body = @email_message&.body.presence ||
|
||||||
template_submitters_index.dig(@submitter.uuid, 'request_email_body').presence ||
|
template_submitters_index.dig(@submitter.uuid, 'request_email_body').presence ||
|
||||||
@@ -36,6 +31,8 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
|
|
||||||
reply_to = build_submitter_reply_to(@submitter)
|
reply_to = build_submitter_reply_to(@submitter)
|
||||||
|
|
||||||
|
maybe_set_custom_domain(@submitter)
|
||||||
|
|
||||||
I18n.with_locale(@current_account.locale) do
|
I18n.with_locale(@current_account.locale) do
|
||||||
subject = build_invite_subject(@subject, @email_config, submitter)
|
subject = build_invite_subject(@subject, @email_config, submitter)
|
||||||
|
|
||||||
@@ -133,6 +130,8 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
assign_message_metadata('submitter_documents_copy', @submitter)
|
assign_message_metadata('submitter_documents_copy', @submitter)
|
||||||
reply_to = build_submitter_reply_to(submitter, email_config: @email_config, documents_copy_email: true)
|
reply_to = build_submitter_reply_to(submitter, email_config: @email_config, documents_copy_email: true)
|
||||||
|
|
||||||
|
maybe_set_custom_domain(@submitter)
|
||||||
|
|
||||||
I18n.with_locale(@current_account.locale) do
|
I18n.with_locale(@current_account.locale) do
|
||||||
subject =
|
subject =
|
||||||
@subject.present? ? ReplaceEmailVariables.call(@subject, submitter:) : I18n.t(:your_document_copy)
|
@subject.present? ? ReplaceEmailVariables.call(@subject, submitter:) : I18n.t(:your_document_copy)
|
||||||
@@ -262,4 +261,10 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
def fetch_config_email_body(email_config, _submitter = nil)
|
def fetch_config_email_body(email_config, _submitter = nil)
|
||||||
email_config ? email_config.value['body'].presence : nil
|
email_config ? email_config.value['body'].presence : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def maybe_set_custom_domain(submitter)
|
||||||
|
if Docuseal.multitenant? && (config = AccountConfig.find_by(account_id: submitter.account_id, key: :custom_domain))
|
||||||
|
@custom_domain = config.value
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class AccountConfig < ApplicationRecord
|
|||||||
WITH_AUDIT_VALUES_KEY = 'with_audit_values'
|
WITH_AUDIT_VALUES_KEY = 'with_audit_values'
|
||||||
WITH_AUDIT_SENDER_KEY = 'with_audit_sender'
|
WITH_AUDIT_SENDER_KEY = 'with_audit_sender'
|
||||||
WITH_SUBMITTER_TIMEZONE_KEY = 'with_submitter_timezone'
|
WITH_SUBMITTER_TIMEZONE_KEY = 'with_submitter_timezone'
|
||||||
|
WITH_TIMESTAMP_SECONDS_KEY = 'with_timestamp_seconds'
|
||||||
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'
|
||||||
@@ -57,6 +58,13 @@ class AccountConfig < ApplicationRecord
|
|||||||
TEMPLATE_CUSTOM_FIELDS_KEY = 'template_custom_fields'
|
TEMPLATE_CUSTOM_FIELDS_KEY = 'template_custom_fields'
|
||||||
POLICY_LINKS_KEY = 'policy_links'
|
POLICY_LINKS_KEY = 'policy_links'
|
||||||
|
|
||||||
|
EMAIL_VARIABLES = {
|
||||||
|
SUBMITTER_INVITATION_EMAIL_KEY => %w[template.name submitter.link account.name].freeze,
|
||||||
|
SUBMITTER_COMPLETED_EMAIL_KEY => %w[template.name submission.submitters submission.link].freeze,
|
||||||
|
SUBMITTER_INVITATION_REMINDER_EMAIL_KEY => %w[template.name submitter.link account.name].freeze,
|
||||||
|
SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY => %w[template.name documents.link account.name].freeze
|
||||||
|
}.freeze
|
||||||
|
|
||||||
DEFAULT_VALUES = {
|
DEFAULT_VALUES = {
|
||||||
SUBMITTER_INVITATION_EMAIL_KEY => lambda {
|
SUBMITTER_INVITATION_EMAIL_KEY => lambda {
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<svg class="<%= local_assigns[:class] %>" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M9 14l-4 -4l4 -4" />
|
||||||
|
<path d="M5 10h11a4 4 0 1 1 0 8h-1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 354 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg class="<%= local_assigns[:class] %>" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M15 14l4 -4l-4 -4" />
|
||||||
|
<path d="M19 10h-11a4 4 0 1 0 0 8h1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 356 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg class="<%= local_assigns[:class] %>" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M7 5h6a3.5 3.5 0 0 1 0 7h-6l0 -7" />
|
||||||
|
<path d="M13 12h1a3.5 3.5 0 0 1 0 7h-7v-7" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 377 B |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg class="<%= local_assigns[:class] %>" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M11 5l6 0" />
|
||||||
|
<path d="M7 19l6 0" />
|
||||||
|
<path d="M14 5l-4 14" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 358 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg class="<%= local_assigns[:class] %>" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M7 5v5a5 5 0 0 0 10 0v-5" />
|
||||||
|
<path d="M5 19h14" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 345 B |
@@ -1,11 +1,5 @@
|
|||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<div class="flex items-center">
|
<%= ff.label :body, t('body'), class: 'label' %>
|
||||||
<%= ff.label :body, t('body'), class: 'label' %>
|
<% variables = AccountConfig::EMAIL_VARIABLES[local_assigns[:config].key] %>
|
||||||
<span class="tooltip" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[local_assigns[:config].key].call['body'].scan(/{.*?}/).join(', ') %>">
|
<%= render 'personalization_settings/markdown_editor', name: ff.field_name(:body), value: local_assigns[:config].value['body'], variables: variables %>
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<autoresize-textarea>
|
|
||||||
<%= ff.text_area :body, required: true, class: 'base-input w-full !rounded-2xl py-2', dir: 'auto' %>
|
|
||||||
</autoresize-textarea>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<% link_tooltip_html = capture do %>
|
||||||
|
<div class="hidden absolute flex bg-white border border-base-300 rounded-xl shadow p-1 gap-1 items-center z-50" contenteditable="false">
|
||||||
|
<input type="text" placeholder="<%= t('enter_a_url_or_variable_name') %>" class="rounded-lg border border-base-300 px-2 py-1 text-sm outline-none" style="field-sizing: content; min-width: 205px; max-width: 320px;" autocomplete="off">
|
||||||
|
<button type="button" data-role="link-save" class="flex items-center px-1 w-6 h-6 rounded hover:bg-success/10 cursor-pointer">
|
||||||
|
<%= svg_icon('check', class: 'w-4 h-4 text-success') %>
|
||||||
|
</button>
|
||||||
|
<button type="button" data-role="link-remove" class="flex items-center px-1 w-6 h-6 rounded hover:bg-error/10 cursor-pointer">
|
||||||
|
<%= svg_icon('x', class: 'w-4 h-4 text-error') %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<markdown-editor data-link-tooltip-html="<%= link_tooltip_html.squish %>">
|
||||||
|
<div class="border border-base-content/20 rounded-2xl bg-white">
|
||||||
|
<div class="flex items-center px-2 py-2 border-b" style="height: 42px;">
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<div class="tooltip tooltip-top before:text-xs" data-tip="<%= t('bold') %> (Ctrl+B)">
|
||||||
|
<button type="button" data-action="click:markdown-editor#bold" data-target="markdown-editor.boldButton" aria-label="<%= t('bold') %>" class="flex items-center px-1 w-6 h-6 rounded hover:bg-base-300">
|
||||||
|
<%= svg_icon('bold', class: 'w-4 h-4') %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip tooltip-top before:text-xs" data-tip="<%= t('italic') %> (Ctrl+I)">
|
||||||
|
<button type="button" data-action="click:markdown-editor#italic" data-target="markdown-editor.italicButton" aria-label="<%= t('italic') %>" class="flex items-center px-1 w-6 h-6 rounded hover:bg-base-300">
|
||||||
|
<%= svg_icon('italic', class: 'w-4 h-4') %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip tooltip-top before:text-xs" data-tip="<%= t('underline') %> (Ctrl+U)">
|
||||||
|
<button type="button" data-action="click:markdown-editor#underline" data-target="markdown-editor.underlineButton" aria-label="<%= t('underline') %>" class="flex items-center px-1 w-6 h-6 rounded hover:bg-base-300">
|
||||||
|
<%= svg_icon('underline', class: 'w-4 h-4') %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip tooltip-top before:text-xs" data-tip="<%= t('link') %> (Ctrl+K)">
|
||||||
|
<button type="button" data-action="click:markdown-editor#linkSelection" data-target="markdown-editor.linkButton" aria-label="<%= t('link') %>" class="flex items-center px-1 w-6 h-6 rounded hover:bg-base-300">
|
||||||
|
<%= svg_icon('link', class: 'w-4 h-4') %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mx-2 h-5 border-l border-base-content/20"></div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<div class="tooltip tooltip-top before:text-xs" data-tip="<%= t('undo') %> (Ctrl+Z)">
|
||||||
|
<button type="button" data-action="click:markdown-editor#undo" data-target="markdown-editor.undoButton" aria-label="<%= t('undo') %>" class="flex items-center px-1 w-6 h-6 rounded hover:bg-base-300">
|
||||||
|
<%= svg_icon('arrow_back_up', class: 'w-4 h-4') %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip tooltip-top before:text-xs" data-tip="<%= t('redo') %> (Ctrl+Shift+Z)">
|
||||||
|
<button type="button" data-action="click:markdown-editor#redo" data-target="markdown-editor.redoButton" aria-label="<%= t('redo') %>" class="flex items-center px-1 w-6 h-6 rounded hover:bg-base-300">
|
||||||
|
<%= svg_icon('arrow_forward_up', class: 'w-4 h-4') %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% if local_assigns[:variables]&.any? %>
|
||||||
|
<% variable_labels = { 'account.name' => t('variables.account_name'), 'submitter.link' => t('variables.submitter_link'), 'template.name' => t('variables.template_name'), 'submission.submitters' => t('variables.submission_submitters'), 'submission.link' => t('variables.submission_link'), 'documents.link' => t('variables.documents_link') } %>
|
||||||
|
<div class="dropdown dropdown-end ml-auto">
|
||||||
|
<label tabindex="0" class="flex items-center gap-1 text-sm px-2 py-1 rounded hover:bg-base-200 cursor-pointer">
|
||||||
|
<%= t('add_variable') %>
|
||||||
|
<%= svg_icon('chevron_down', class: 'w-3.5 h-3.5') %>
|
||||||
|
</label>
|
||||||
|
<div tabindex="0" class="dropdown-content right-0 top-full mt-1 p-1 bg-white border border-neutral-200 rounded-lg shadow-lg z-50">
|
||||||
|
<% local_assigns[:variables]&.each do |variable| %>
|
||||||
|
<button type="button" data-variable="<%= variable %>" data-action="click:markdown-editor#insertVariable" class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 text-left text-sm cursor-pointer whitespace-nowrap">
|
||||||
|
<%= variable_labels.fetch(variable, "{#{variable}}") %>
|
||||||
|
</button>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<div data-target="markdown-editor.editorElement"></div>
|
||||||
|
</div>
|
||||||
|
<%= hidden_field_tag name, value, required: true, data: { target: 'markdown-editor.textarea' } %>
|
||||||
|
</markdown-editor>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<%= ff.label :subject, t('subject'), class: 'label' %>
|
<%= ff.label :subject, t('subject'), class: 'label' %>
|
||||||
<span class="tooltip" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY].call['subject'].scan(/{.*?}/).join(', ') %>">
|
<span class="tooltip" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::EMAIL_VARIABLES[AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY].map { |v| "{#{v}}" }.join(', ') %>">
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<% if configs = account.account_configs.find_by(key: AccountConfig::POLICY_LINKS_KEY) %>
|
<% if configs = account.account_configs.find_by(key: AccountConfig::POLICY_LINKS_KEY) %>
|
||||||
<div class="max-w-md mx-auto flex flex-wrap gap-1 justify-center text-sm text-base-content/60 mt-2">
|
<div class="max-w-md mx-auto flex flex-wrap gap-1 justify-center text-sm text-base-content/60 mt-2">
|
||||||
<%= auto_link(MarkdownToHtml.call(configs.value)) %>
|
<%= MarkdownToHtml.call(configs.value) %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<% has_phone_field = false %>
|
<% has_phone_field = false %>
|
||||||
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
||||||
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? } %>
|
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? || e['invite_via_field_uuid'].present? } %>
|
||||||
<dynamic-list class="space-y-4">
|
<dynamic-list class="space-y-4">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="card card-compact bg-base-300/40" data-targets="dynamic-list.items">
|
<div class="card card-compact bg-base-300/40" data-targets="dynamic-list.items">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
||||||
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? } %>
|
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? || e['invite_via_field_uuid'].present? } %>
|
||||||
<% if submitters.size == 1 %>
|
<% if submitters.size == 1 %>
|
||||||
<submitter-item class="form-control">
|
<submitter-item class="form-control">
|
||||||
<emails-textarea data-bulk-enabled="<%= Docuseal.demo? || !Docuseal.multitenant? || can?(:manage, :bulk_send) %>" data-limit="<%= Docuseal.multitenant? ? (can?(:manage, :bulk_send) ? 40 : 1) : nil %>">
|
<emails-textarea data-bulk-enabled="<%= Docuseal.demo? || !Docuseal.multitenant? || can?(:manage, :bulk_send) %>" data-limit="<%= Docuseal.multitenant? ? (can?(:manage, :bulk_send) ? 40 : 1) : nil %>">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
||||||
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? } %>
|
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? || e['invite_via_field_uuid'].present? } %>
|
||||||
<dynamic-list class="space-y-4">
|
<dynamic-list class="space-y-4">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="card card-compact bg-base-300/40" data-targets="dynamic-list.items">
|
<div class="card card-compact bg-base-300/40" data-targets="dynamic-list.items">
|
||||||
|
|||||||
@@ -55,15 +55,9 @@
|
|||||||
<%= f.text_field :subject, value: local_assigns[:submitter_email_message]&.subject.presence || submitter_preferences_index.dig(local_assigns[:submitter]&.uuid, 'request_email_subject').presence || template&.preferences&.dig('request_email_subject').presence || config.value['subject'], required: true, class: '!text-sm base-input w-full', dir: 'auto' %>
|
<%= f.text_field :subject, value: local_assigns[:submitter_email_message]&.subject.presence || submitter_preferences_index.dig(local_assigns[:submitter]&.uuid, 'request_email_subject').presence || template&.preferences&.dig('request_email_subject').presence || config.value['subject'], required: true, class: '!text-sm base-input w-full', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<div class="flex items-center">
|
<%= f.label :message, t('body'), class: 'label' %>
|
||||||
<%= f.label :message, t('body'), class: 'label' %>
|
<% body_variables = AccountConfig::EMAIL_VARIABLES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY] %>
|
||||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
<%= render 'personalization_settings/markdown_editor', name: f.field_name(:body), value: local_assigns[:submitter_email_message]&.body.presence || submitter_preferences_index.dig(local_assigns[:submitter]&.uuid, 'request_email_body').presence || template&.preferences&.dig('request_email_body').presence || config.value['body'], variables: body_variables %>
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<autoresize-textarea>
|
|
||||||
<%= f.text_area :body, value: local_assigns[:submitter_email_message]&.body.presence || submitter_preferences_index.dig(local_assigns[:submitter]&.uuid, 'request_email_body').presence || template&.preferences&.dig('request_email_body').presence || config.value['body'], required: true, class: 'base-textarea w-full', rows: 10, dir: 'auto' %>
|
|
||||||
</autoresize-textarea>
|
|
||||||
<% unless local_assigns.fetch(:disable_save_as_default_template_option, false) %>
|
<% unless local_assigns.fetch(:disable_save_as_default_template_option, false) %>
|
||||||
<label for="<%= uuid = SecureRandom.uuid %>" class="flex items-center cursor-pointer">
|
<label for="<%= uuid = SecureRandom.uuid %>" class="flex items-center cursor-pointer">
|
||||||
<%= check_box_tag :save_message, id: uuid, class: 'base-checkbox', checked: false %>
|
<%= check_box_tag :save_message, id: uuid, class: 'base-checkbox', checked: false %>
|
||||||
@@ -97,15 +91,8 @@
|
|||||||
<%= ff.text_field :subject, value: local_assigns[:submitter_email_message]&.subject.presence || submitter_preferences_index.dig(submitter['uuid'], 'request_email_subject').presence || template&.preferences&.dig('request_email_subject').presence || config.value['subject'], required: true, class: '!text-sm base-input w-full', dir: 'auto' %>
|
<%= ff.text_field :subject, value: local_assigns[:submitter_email_message]&.subject.presence || submitter_preferences_index.dig(submitter['uuid'], 'request_email_subject').presence || template&.preferences&.dig('request_email_subject').presence || config.value['subject'], required: true, class: '!text-sm base-input w-full', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<div class="flex items-center">
|
<%= ff.label :message, t('body'), class: 'label' %>
|
||||||
<%= ff.label :message, t('body'), class: 'label' %>
|
<%= render 'personalization_settings/markdown_editor', name: ff.field_name(:body), value: local_assigns[:submitter_email_message]&.body.presence || submitter_preferences_index.dig(submitter['uuid'], 'request_email_body').presence || template&.preferences&.dig('request_email_body').presence || config.value['body'], variables: body_variables %>
|
||||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<autoresize-textarea>
|
|
||||||
<%= ff.text_area :body, value: local_assigns[:submitter_email_message]&.body.presence || submitter_preferences_index.dig(submitter['uuid'], 'request_email_body').presence || template&.preferences&.dig('request_email_body').presence || config.value['body'], required: true, class: 'base-textarea w-full', rows: 10, dir: 'auto' %>
|
|
||||||
</autoresize-textarea>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -28,7 +28,8 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<div>
|
<div>
|
||||||
<% timezone = local_assigns[:with_submitter_timezone] ? (submitter.timezone || local_assigns[:timezone]) : local_assigns[:timezone] %>
|
<% timezone = local_assigns[:with_submitter_timezone] ? (submitter.timezone || local_assigns[:timezone]) : local_assigns[:timezone] %>
|
||||||
<%= l(attachment.created_at.in_time_zone(timezone), format: :long, locale: local_assigns[:locale]) %> <%= TimeUtils.timezone_abbr(timezone, attachment.created_at) %>
|
<% time_format = local_assigns[:with_timestamp_seconds] ? :detailed : :long %>
|
||||||
|
<%= l(attachment.created_at.in_time_zone(timezone), format: time_format, locale: local_assigns[:locale]) %> <%= TimeUtils.timezone_abbr(timezone, attachment.created_at) %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
<%= render 'submissions/preview_tags' %>
|
<%= render 'submissions/preview_tags' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% font_scale = 1040.0 / PdfUtils::US_LETTER_W %>
|
<% font_scale = 1040.0 / PdfUtils::US_LETTER_W %>
|
||||||
<% configs = AccountConfig.where(account_id: @submission.account_id, key: [AccountConfig::COMBINE_PDF_RESULT_KEY, AccountConfig::WITH_SIGNATURE_ID, AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY, AccountConfig::WITH_SIGNATURE_ID_REASON_KEY]) %>
|
<% configs = AccountConfig.where(account_id: @submission.account_id, key: [AccountConfig::COMBINE_PDF_RESULT_KEY, AccountConfig::WITH_SIGNATURE_ID, AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY, AccountConfig::WITH_SIGNATURE_ID_REASON_KEY, AccountConfig::WITH_TIMESTAMP_SECONDS_KEY]) %>
|
||||||
<% with_signature_id = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID }&.value == true %>
|
<% with_signature_id = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID }&.value == true %>
|
||||||
<% is_combined_enabled = configs.find { |e| e.key == AccountConfig::COMBINE_PDF_RESULT_KEY }&.value == true && !@submission.template_fields&.any? { |f| f['type'] == 'verification' } %>
|
<% is_combined_enabled = configs.find { |e| e.key == AccountConfig::COMBINE_PDF_RESULT_KEY }&.value == true && !@submission.template_fields&.any? { |f| f['type'] == 'verification' } %>
|
||||||
<% with_submitter_timezone = configs.find { |e| e.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true %>
|
<% with_submitter_timezone = configs.find { |e| e.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true %>
|
||||||
|
<% with_timestamp_seconds = configs.find { |e| e.key == AccountConfig::WITH_TIMESTAMP_SECONDS_KEY }&.value == true %>
|
||||||
<% with_signature_id_reason = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false %>
|
<% with_signature_id_reason = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false %>
|
||||||
<div style="max-width: 1600px" class="mx-auto pl-4">
|
<div style="max-width: 1600px" class="mx-auto pl-4">
|
||||||
<div class="flex justify-between py-1.5 items-center pr-4 sticky top-0 md:relative z-10 bg-base-100">
|
<div class="flex justify-between py-1.5 items-center pr-4 sticky top-0 md:relative z-10 bg-base-100">
|
||||||
@@ -20,7 +21,7 @@
|
|||||||
<%= button_to button_title(title: t('unarchive'), disabled_with: t('unarchive')[0..-2], icon: svg_icon('rotate', class: 'w-6 h-6')), submission_unarchive_index_path(@submission), class: 'btn btn-primary btn-ghost text-base hidden md:flex' %>
|
<%= button_to button_title(title: t('unarchive'), disabled_with: t('unarchive')[0..-2], icon: svg_icon('rotate', class: 'w-6 h-6')), submission_unarchive_index_path(@submission), class: 'btn btn-primary btn-ghost text-base hidden md:flex' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @submission.audit_trail.present? %>
|
<% if @submission.audit_trail.present? %>
|
||||||
<a href="<%= ActiveStorage::Blob.proxy_url(@submission.audit_trail.blob, expires_at: 4.hours.from_now) %>" class="white-button" target="_blank">
|
<a href="<%= ActiveStorage::Blob.proxy_path(@submission.audit_trail.blob, expires_at: 4.hours.from_now) %>" class="white-button" target="_blank">
|
||||||
<%= svg_icon('external_link', class: 'w-6 h-6') %>
|
<%= svg_icon('external_link', class: 'w-6 h-6') %>
|
||||||
<span class="hidden md:inline"><%= t('audit_log') %></span>
|
<span class="hidden md:inline"><%= t('audit_log') %></span>
|
||||||
</a>
|
</a>
|
||||||
@@ -125,7 +126,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index:, value: mask.present? ? Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', ') : value, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id:, with_submitter_timezone:, with_signature_id_reason: %>
|
<%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index:, value: mask.present? ? Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', ') : value, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id:, with_submitter_timezone:, with_timestamp_seconds:, with_signature_id_reason: %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% elsif field['readonly'] != true && submitter && !submitter.completed_at? %>
|
<% elsif field['readonly'] != true && submitter && !submitter.completed_at? %>
|
||||||
<% submitters_order_index ||= (@submission.template_submitters || @submission.template.submitters).each_with_index.to_h { |s, i| [s['uuid'], i] } %>
|
<% submitters_order_index ||= (@submission.template_submitters || @submission.template.submitters).each_with_index.to_h { |s, i| [s['uuid'], i] } %>
|
||||||
|
|||||||
@@ -80,7 +80,7 @@
|
|||||||
<% next if field['conditions'].present? && values[field['uuid']].blank? && field['submitter_uuid'] != @submitter.uuid %>
|
<% next if field['conditions'].present? && values[field['uuid']].blank? && field['submitter_uuid'] != @submitter.uuid %>
|
||||||
<% next if field['conditions'].present? && field['submitter_uuid'] == @submitter.uuid %>
|
<% next if field['conditions'].present? && field['submitter_uuid'] == @submitter.uuid %>
|
||||||
<% next if field.dig('preferences', 'formula').present? && field['submitter_uuid'] == @submitter.uuid %>
|
<% next if field.dig('preferences', 'formula').present? && field['submitter_uuid'] == @submitter.uuid %>
|
||||||
<%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index: @attachments_index, value: field.dig('preferences', 'mask').present? ? TextUtils.mask_value(value, field.dig('preferences', 'mask')) : value, locale: @submitter.account.locale, timezone: @submitter.account.timezone, submitter: submitters_index[field['submitter_uuid']], with_signature_id: @form_configs[:with_signature_id], with_submitter_timezone: @form_configs[:with_submitter_timezone], with_signature_id_reason: @form_configs[:with_signature_id_reason] %>
|
<%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index: @attachments_index, value: field.dig('preferences', 'mask').present? ? TextUtils.mask_value(value, field.dig('preferences', 'mask')) : value, locale: @submitter.account.locale, timezone: @submitter.account.timezone, submitter: submitters_index[field['submitter_uuid']], with_signature_id: @form_configs[:with_signature_id], with_submitter_timezone: @form_configs[:with_submitter_timezone], with_timestamp_seconds: @form_configs[:with_timestamp_seconds], with_signature_id_reason: @form_configs[:with_signature_id_reason] %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</page-container>
|
</page-container>
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
<% if @form_configs[:policy_links].present? %>
|
<% if @form_configs[:policy_links].present? %>
|
||||||
<div class="text-center md:text-neutral-500 md:pr-3 md:pb-3 md:text-sm md:text-left mt-2 md:mt-0 md:fixed md:bottom-0 md:right-0">
|
<div class="text-center md:text-neutral-500 md:pr-3 md:pb-3 md:text-sm md:text-left mt-2 md:mt-0 md:fixed md:bottom-0 md:right-0">
|
||||||
<div class="md:max-w-[8rem] flex flex-wrap md:flex-col justify-center md:justify-start md:items-start space-x-2 md:space-x-0">
|
<div class="md:max-w-[8rem] flex flex-wrap md:flex-col justify-center md:justify-start md:items-start space-x-2 md:space-x-0">
|
||||||
<%= auto_link(MarkdownToHtml.call(@form_configs[:policy_links])) %>
|
<%= MarkdownToHtml.call(@form_configs[:policy_links]) %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<%= auto_link(simple_format(MarkdownToHtml.call(h(ReplaceEmailVariables.call(local_assigns[:content], submitter: local_assigns[:submitter], sig: local_assigns[:sig]))))) %>
|
<%= MarkdownToHtml.call(ReplaceEmailVariables.call(local_assigns[:content], submitter: local_assigns[:submitter], sig: local_assigns[:sig])) %>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<p><%= t('please_check_the_copy_of_your_name_in_the_email_attachments', name: @submitter.submission.name || @submitter.submission.template.name) %>
|
<p><%= t('please_check_the_copy_of_your_name_in_the_email_attachments', name: @submitter.submission.name || @submitter.submission.template.name) %>
|
||||||
<p><%= t('alternatively_you_can_review_and_download_your_copy_using_the_link_below') %></p>
|
<p><%= t('alternatively_you_can_review_and_download_your_copy_using_the_link_below') %></p>
|
||||||
<p>
|
<p>
|
||||||
<%= link_to @submitter.submission.name || @submitter.submission.template.name, submissions_preview_url(@submitter.submission.slug, { sig: @sig }.compact) %>
|
<%= link_to @submitter.submission.name || @submitter.submission.template.name, submissions_preview_url(@submitter.submission.slug, { sig: @sig, host: @custom_domain || ENV.fetch('EMAIL_HOST', Docuseal.default_url_options[:host]) }.compact) %>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<%= t('thanks') %>,<br><%= @current_account.name %>
|
<%= t('thanks') %>,<br><%= @current_account.name %>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<% if @body.present? %>
|
<% if @body.present? %>
|
||||||
<%= render 'custom_content', content: @body, submitter: @submitter %>
|
<%= render 'custom_content', content: @body, submitter: @submitter %>
|
||||||
<% if !@body.match?(ReplaceEmailVariables::SUBMITTER_LINK) && !@body.match?(ReplaceEmailVariables::SUBMITTER_ID) && !@body.match?(ReplaceEmailVariables::SUBMISSION_LINK) && !@body.match?(ReplaceEmailVariables::TEMPLATE_ID) && !@submitter.submission.source.in?(%w[api embed]) %>
|
<% if !@body.match?(ReplaceEmailVariables::SUBMITTER_LINK) && !@body.match?(ReplaceEmailVariables::SUBMITTER_ID) && !@body.match?(ReplaceEmailVariables::SUBMISSION_LINK) && !@body.match?(ReplaceEmailVariables::TEMPLATE_ID) && !@submitter.submission.source.in?(%w[api embed]) %>
|
||||||
<p><%= link_to nil, submit_form_url(slug: @submitter.slug, t: SubmissionEvents.build_tracking_param(@submitter, 'click_email')) %></p>
|
<p><%= link_to nil, submit_form_url(slug: @submitter.slug, t: SubmissionEvents.build_tracking_param(@submitter, 'click_email'), host: @custom_domain || ENV.fetch('EMAIL_HOST', Docuseal.default_url_options[:host])) %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p><%= t('hi_there') %>,</p>
|
<p><%= t('hi_there') %>,</p>
|
||||||
<p><%= I18n.t(@submitter.with_signature_fields? ? :you_have_been_invited_to_sign_the_name : :you_have_been_invited_to_submit_the_name_form, name: @submitter.submission.name || @submitter.submission.template.name) %></p>
|
<p><%= I18n.t(@submitter.with_signature_fields? ? :you_have_been_invited_to_sign_the_name : :you_have_been_invited_to_submit_the_name_form, name: @submitter.submission.name || @submitter.submission.template.name) %></p>
|
||||||
<p><%= link_to I18n.t(@submitter.with_signature_fields? ? :review_and_sign : :review_and_submit), submit_form_url(slug: @submitter.slug, t: SubmissionEvents.build_tracking_param(@submitter, 'click_email'), host: ENV.fetch('EMAIL_HOST', Docuseal.default_url_options[:host])) %></p>
|
<p><%= link_to I18n.t(@submitter.with_signature_fields? ? :review_and_sign : :review_and_submit), submit_form_url(slug: @submitter.slug, t: SubmissionEvents.build_tracking_param(@submitter, 'click_email'), host: @custom_domain || ENV.fetch('EMAIL_HOST', Docuseal.default_url_options[:host])) %></p>
|
||||||
<p><%= t('please_contact_us_by_replying_to_this_email_if_you_have_any_questions') %></p>
|
<p><%= t('please_contact_us_by_replying_to_this_email_if_you_have_any_questions') %></p>
|
||||||
<p>
|
<p>
|
||||||
<%= t('thanks') %>,<br><%= @current_account.name %>
|
<%= t('thanks') %>,<br><%= @current_account.name %>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
<% elsif !submission.archived_at? && !template&.archived_at? && !submission.expired? && !submitter.declined_at? %>
|
<% elsif !submission.archived_at? && !template&.archived_at? && !submission.expired? && !submitter.declined_at? %>
|
||||||
<% if current_user.email == submitter.email %>
|
<% if current_user.email == submitter.email %>
|
||||||
<div class="flex-1 md:flex-none md:w-36 flex">
|
<div class="flex-1 md:flex-none md:w-36 flex">
|
||||||
<a href="<%= submit_form_url(slug: submitter.slug) %>" data-turbo="false" target="_blank" id="sign_yourself_button" class="btn btn-sm btn-neutral btn-outline bg-white w-full md:w-36 flex z-[1]">
|
<a href="<%= submit_form_path(slug: submitter.slug) %>" data-turbo="false" target="_blank" id="sign_yourself_button" class="btn btn-sm btn-neutral btn-outline bg-white w-full md:w-36 flex z-[1]">
|
||||||
<span class="flex items-center justify-center space-x-1 md:space-x-2">
|
<span class="flex items-center justify-center space-x-1 md:space-x-2">
|
||||||
<% if t('sign_now').length < 12 %>
|
<% if t('sign_now').length < 12 %>
|
||||||
<%= svg_icon('writing_sign', class: 'w-4 h-4 stroke-2') %>
|
<%= svg_icon('writing_sign', class: 'w-4 h-4 stroke-2') %>
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
<% elsif !template&.archived_at? && !submission.archived_at? && !is_submission_completed && !submission.expired? && !submitter.declined_at? %>
|
<% elsif !template&.archived_at? && !submission.archived_at? && !is_submission_completed && !submission.expired? && !submitter.declined_at? %>
|
||||||
<div class="relative flex items-center space-x-3">
|
<div class="relative flex items-center space-x-3">
|
||||||
<% if current_user.email == submitter.email %>
|
<% if current_user.email == submitter.email %>
|
||||||
<a href="<%= submit_form_url(slug: submitter.slug) %>" data-turbo="false" target="_blank" id="sign_yourself_button" class="absolute md:relative top-0 right-0 btn btn-xs btn-outline btn-neutral bg-white w-28 md:w-36 z-[1]">
|
<a href="<%= submit_form_path(slug: submitter.slug) %>" data-turbo="false" target="_blank" id="sign_yourself_button" class="absolute md:relative top-0 right-0 btn btn-xs btn-outline btn-neutral bg-white w-28 md:w-36 z-[1]">
|
||||||
<span class="flex items-center justify-center space-x-1 md:space-x-2">
|
<span class="flex items-center justify-center space-x-1 md:space-x-2">
|
||||||
<% if t('sign_now').length < 12 %>
|
<% if t('sign_now').length < 12 %>
|
||||||
<%= svg_icon('writing_sign', class: 'w-4 h-4 stroke-2') %>
|
<%= svg_icon('writing_sign', class: 'w-4 h-4 stroke-2') %>
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
<span class="mr-1"><%= t('send_to_recipients') %></span>
|
<span class="mr-1"><%= t('send_to_recipients') %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @template.submitters.size == 1 %>
|
<% if Templates.filter_undefined_submitters(@template.submitters).size == 1 %>
|
||||||
<%= button_to start_form_path(@template.slug), params: { selfsign: true }, method: :put, class: 'white-button w-full', form: { style: 'display: inline', target: '_blank', data: { turbo: false } } do %>
|
<%= button_to start_form_path(@template.slug), params: { selfsign: true }, method: :put, class: 'white-button w-full', form: { style: 'display: inline', target: '_blank', data: { turbo: false } } do %>
|
||||||
<%= svg_icon('writing', class: 'w-6 h-6') %>
|
<%= svg_icon('writing', class: 'w-6 h-6') %>
|
||||||
<span class="mr-1"><%= t('sign_it_yourself') %></span>
|
<span class="mr-1"><%= t('sign_it_yourself') %></span>
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
<div class="space-y-3 divide-y">
|
<div class="space-y-3 divide-y">
|
||||||
<% template.submitters.each_with_index do |submitter, index| %>
|
<% template.submitters.each_with_index do |submitter, index| %>
|
||||||
<div class="<%= 'pt-3' if index.positive? %>">
|
<div class="<%= 'pt-3' if index.positive? %>">
|
||||||
<%= f.fields_for :submitters, item = Struct.new(:name, :uuid, :is_requester, :email, :invite_by_uuid, :optional_invite_by_uuid, :linked_to_uuid, :order, :option).new(*submitter.values_at('name', 'uuid', 'is_requester', 'email', 'invite_by_uuid', 'optional_invite_by_uuid', 'linked_to_uuid', 'order')), index: do |ff| %>
|
<%= f.fields_for :submitters, item = Struct.new(:name, :uuid, :is_requester, :email, :invite_by_uuid, :invite_via_field_uuid, :optional_invite_by_uuid, :linked_to_uuid, :order, :option).new(*submitter.values_at('name', 'uuid', 'is_requester', 'email', 'invite_by_uuid', 'invite_via_field_uuid', 'optional_invite_by_uuid', 'linked_to_uuid', 'order')), index: do |ff| %>
|
||||||
<% item.option = item.is_requester.present? ? 'is_requester' : (item.email.present? ? 'email' : (item.linked_to_uuid.present? ? "linked_to_#{item.linked_to_uuid}" : (item.invite_by_uuid.present? ? "invite_by_#{item.invite_by_uuid}" : (item.optional_invite_by_uuid.present? ? "optional_invite_by_#{item.optional_invite_by_uuid}" : '')))) %>
|
<% item.option = item.is_requester.present? ? 'is_requester' : (item.email.present? ? 'email' : (item.linked_to_uuid.present? ? "linked_to_#{item.linked_to_uuid}" : (item.invite_by_uuid.present? ? "invite_by_#{item.invite_by_uuid}" : (item.optional_invite_by_uuid.present? ? "optional_invite_by_#{item.optional_invite_by_uuid}" : (item.invite_via_field_uuid.present? ? 'invite_via_field' : ''))))) %>
|
||||||
<%= ff.hidden_field :uuid %>
|
<%= ff.hidden_field :uuid %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
@@ -26,35 +26,71 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% if template.submitters.size == 2 %>
|
<% if template.submitters.size == 2 %>
|
||||||
<%= tag.input name: ff.field_name(:email), value: ff.object.email, type: :email, class: 'base-input', multiple: true, autocomplete: 'off', placeholder: t('default_email'), disabled: ff.object.is_requester || ff.object.invite_by_uuid.present? || ff.object.optional_invite_by_uuid.present?, id: field_uuid = SecureRandom.uuid %>
|
<%= tag.input name: ff.field_name(:email), value: ff.object.email, type: :email, multiple: true, autocomplete: 'off', placeholder: t('default_email'), id: email_field_uuid = SecureRandom.uuid, disabled: is_email_disabled = ff.object.is_requester || ff.object.invite_by_uuid.present? || ff.object.optional_invite_by_uuid.present? || ff.object.invite_via_field_uuid.present?, class: "base-input w-full #{'hidden' if ff.object.invite_by_uuid.present? || ff.object.optional_invite_by_uuid.present? || ff.object.invite_via_field_uuid.present?}" %>
|
||||||
|
<% if index == 1 %>
|
||||||
|
<% invite_fields = template.fields.select { |field| field['name'].present? && field['submitter_uuid'] != submitter['uuid'] } %>
|
||||||
|
<disable-hidden id="<%= invite_by_selector_id = SecureRandom.uuid %>" class="<%= 'hidden' if ff.object.invite_by_uuid.blank? && ff.object.optional_invite_by_uuid.blank? && ff.object.invite_via_field_uuid.blank? %>">
|
||||||
|
<toggle-attribute data-target-id="<%= invite_via_field_selector_id = SecureRandom.uuid %>" data-class-name="hidden" data-value="invite_via_field">
|
||||||
|
<%= ff.select :option, [*(template.submitters - [submitter]).flat_map { |e| [[t('invite_by_name', name: e['name']), "invite_by_#{e['uuid']}"], [t('invite_by_name', name: e['name']) + " (#{t(:optional).capitalize})", "optional_invite_by_#{e['uuid']}"]] }, (invite_fields.present? ? [t('invite_via_form_field'), 'invite_via_field'] : nil)].compact, {}, class: 'base-select' %>
|
||||||
|
</toggle-attribute>
|
||||||
|
<% if invite_fields.present? %>
|
||||||
|
<disable-hidden id="<%= invite_via_field_selector_id %>" class="mt-2 <%= 'hidden' if ff.object.invite_via_field_uuid.blank? %>">
|
||||||
|
<%= select_tag ff.field_name(:invite_via_field_uuid), options_for_select(invite_fields.map { |field| [field['name'], field['uuid']] }, ff.object.invite_via_field_uuid), prompt: t(:select_field), class: 'base-select mt-3' %>
|
||||||
|
</disable-hidden>
|
||||||
|
<% end %>
|
||||||
|
</disable-hidden>
|
||||||
|
<% end %>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
<% invite_fields = template.fields.select { |field| field['name'].present? && field['submitter_uuid'] != submitter['uuid'] } %>
|
||||||
<toggle-attribute data-target-id="<%= email_field_uuid = SecureRandom.uuid %>" data-class-name="hidden" data-value="email">
|
<toggle-attribute data-target-id="<%= email_field_uuid = SecureRandom.uuid %>" data-class-name="hidden" data-value="email">
|
||||||
<%= ff.select :option, [[t('not_specified'), 'not_set'], (local_assigns[:with_submission_requester] == false ? nil : [t('submission_requester'), 'is_requester']), [t('specified_email'), 'email'], *(template.submitters - [submitter]).flat_map { |e| [[t('invite_by_name', name: e['name']), "invite_by_#{e['uuid']}"], [t('invite_by_name', name: e['name']) + " (#{t(:optional).capitalize})", "optional_invite_by_#{e['uuid']}"]] }, *(template.submitters - [submitter]).map { |e| [t('same_as_name', name: e['name']), "linked_to_#{e['uuid']}"] }].compact, {}, class: 'base-select mb-3' %>
|
<toggle-attribute data-target-id="<%= invite_field_wrapper_uuid = SecureRandom.uuid %>" data-class-name="hidden" data-value="invite_via_field">
|
||||||
|
<%= ff.select :option, [[t('not_specified'), 'not_set'], (local_assigns[:with_submission_requester] == false ? nil : [t('submission_requester'), 'is_requester']), [t('specified_email'), 'email'], *(template.submitters - [submitter]).flat_map { |e| [[t('invite_by_name', name: e['name']), "invite_by_#{e['uuid']}"], [t('invite_by_name', name: e['name']) + " (#{t(:optional).capitalize})", "optional_invite_by_#{e['uuid']}"]] }, *(template.submitters - [submitter]).map { |e| [t('same_as_name', name: e['name']), "linked_to_#{e['uuid']}"] }, (invite_fields.present? ? [t('invite_via_form_field'), 'invite_via_field'] : nil)].compact, {}, class: 'base-select mb-3' %>
|
||||||
|
</toggle-attribute>
|
||||||
</toggle-attribute>
|
</toggle-attribute>
|
||||||
<%= tag.input name: ff.field_name(:email), type: :email, value: ff.object.email, multiple: true, class: "base-input #{'hidden' if item.option != 'email'}", autocomplete: 'off', placeholder: t('default_email'), id: email_field_uuid %>
|
<%= tag.input name: ff.field_name(:email), type: :email, value: ff.object.email, multiple: true, class: "base-input #{'hidden' if item.option != 'email'}", autocomplete: 'off', placeholder: t('default_email'), id: email_field_uuid %>
|
||||||
|
<% if invite_fields.present? %>
|
||||||
|
<disable-hidden id="<%= invite_field_wrapper_uuid %>" class="<%= 'hidden' if item.option != 'invite_via_field' %>">
|
||||||
|
<%= select_tag ff.field_name(:invite_via_field_uuid), options_for_select(invite_fields.map { |field| [field['name'], field['uuid']] }, item.invite_via_field_uuid), prompt: t(:select_field), class: 'base-select', required: true %>
|
||||||
|
</disable-hidden>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% if template.submitters.size == 2 %>
|
<% if template.submitters.size == 2 %>
|
||||||
<checkbox-group class="mt-3 flex items-center space-x-4">
|
<checkbox-group class="mt-3 flex items-center space-x-4">
|
||||||
<% if local_assigns[:with_submission_requester] != false %>
|
<% if index == 0 && local_assigns[:with_submission_requester] != false %>
|
||||||
<label class="flex items-center space-x-2 cursor-pointer">
|
<label class="flex items-center space-x-2 cursor-pointer">
|
||||||
<toggle-attribute data-target-id="<%= field_uuid %>" class="flex" data-attribute="disabled">
|
<toggle-attribute data-target-id="<%= email_field_uuid %>" class="flex" data-attribute="disabled">
|
||||||
<%= ff.check_box :is_requester, class: 'base-checkbox' %>
|
<%= ff.check_box :is_requester, class: 'base-checkbox' %>
|
||||||
</toggle-attribute>
|
</toggle-attribute>
|
||||||
<span class="select-none">
|
<span class="select-none">
|
||||||
<%= t('submission_requester') %>
|
<%= t('submission_requester') %>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<% end %>
|
<% elsif index == 1 %>
|
||||||
<% if index == 1 %>
|
<% if local_assigns[:with_submission_requester] != false %>
|
||||||
|
<toggle-classes data-target-id="<%= invite_by_selector_id %>" class="flex" data-classes="hidden" data-action="add">
|
||||||
|
<toggle-classes data-target-id="<%= email_field_uuid %>" class="flex" data-classes="hidden" data-action="remove">
|
||||||
|
<label class="flex items-center space-x-2 cursor-pointer">
|
||||||
|
<toggle-attribute data-target-id="<%= email_field_uuid %>" class="flex" data-attribute="disabled">
|
||||||
|
<%= ff.check_box :is_requester, class: 'base-checkbox' %>
|
||||||
|
</toggle-attribute>
|
||||||
|
<span class="select-none">
|
||||||
|
<%= t('submission_requester') %>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</toggle-classes>
|
||||||
|
</toggle-classes>
|
||||||
|
<% end %>
|
||||||
<label class="flex items-center space-x-2 cursor-pointer">
|
<label class="flex items-center space-x-2 cursor-pointer">
|
||||||
<toggle-attribute data-target-id="<%= field_uuid %>" class="flex" data-attribute="disabled">
|
<toggle-attribute data-target-id="<%= email_field_uuid %>" class="flex" data-class-name="hidden" data-value="false">
|
||||||
<indeterminate-checkbox data-indeterminate="<%= ff.object.optional_invite_by_uuid.present? %>" data-show-indeterminate-id="invite_optional" data-name="<%= ff.field_name(:invite_by_uuid) %>" data-indeterminate-name="<%= ff.field_name(:optional_invite_by_uuid) %>" class="flex">
|
<toggle-attribute data-target-id="<%= invite_by_selector_id %>" class="flex" data-class-name="hidden">
|
||||||
<%= ff.check_box ff.object.optional_invite_by_uuid.present? ? :optional_invite_by_uuid : :invite_by_uuid, { class: 'base-checkbox' }, template.submitters.first['uuid'], '' %>
|
<toggle-attribute data-target-id="<%= email_field_uuid %>" class="flex" data-attribute="disabled">
|
||||||
</indeterminate-checkbox>
|
<%= ff.check_box :invite_checbox, { class: 'base-checkbox', checked: ff.object.invite_by_uuid.present? || ff.object.optional_invite_by_uuid.present? || ff.object.invite_via_field_uuid.present? }, true, '' %>
|
||||||
|
</toggle-attribute>
|
||||||
|
</toggle-attribute>
|
||||||
</toggle-attribute>
|
</toggle-attribute>
|
||||||
<span class="select-none">
|
<span class="select-none">
|
||||||
<%= t('invite_by_name', name: template.submitters.first['name']) %> <span id="invite_optional" class="<%= 'hidden' if ff.object.optional_invite_by_uuid.blank? %>">(<%= t(:optional).capitalize %>)</span>
|
<%= t('invite_by_name', name: template.submitters.first['name']) %>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -20,15 +20,8 @@
|
|||||||
<%= ff.text_field :completed_notification_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
<%= ff.text_field :completed_notification_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<div class="flex items-center">
|
<%= ff.label :completed_notification_email_body, t('email_body'), class: 'label' %>
|
||||||
<%= ff.label :completed_notification_email_body, t('email_body'), class: 'label' %>
|
<%= render 'personalization_settings/markdown_editor', name: ff.field_name(:completed_notification_email_body), value: ff.object.completed_notification_email_body, variables: AccountConfig::EMAIL_VARIABLES[AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY] %>
|
||||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<autoresize-textarea>
|
|
||||||
<%= ff.text_area :completed_notification_email_body, required: true, class: 'base-input w-full py-2 !rounded-2xl', dir: 'auto' %>
|
|
||||||
</autoresize-textarea>
|
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -20,15 +20,8 @@
|
|||||||
<%= ff.text_field :documents_copy_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
<%= ff.text_field :documents_copy_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<div class="flex items-center">
|
<%= ff.label :documents_copy_email_body, t('email_body'), class: 'label' %>
|
||||||
<%= ff.label :documents_copy_email_body, t('email_body'), class: 'label' %>
|
<%= render 'personalization_settings/markdown_editor', name: ff.field_name(:documents_copy_email_body), value: ff.object.documents_copy_email_body, variables: AccountConfig::EMAIL_VARIABLES[AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY] %>
|
||||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<autoresize-textarea>
|
|
||||||
<%= ff.text_area :documents_copy_email_body, required: true, class: 'base-input w-full py-2 !rounded-2xl', dir: 'auto' %>
|
|
||||||
</autoresize-textarea>
|
|
||||||
</div>
|
</div>
|
||||||
<% if can?(:manage, :reply_to) %>
|
<% if can?(:manage, :reply_to) %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
|
|||||||
@@ -27,15 +27,8 @@
|
|||||||
<%= ff.text_field :request_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
<%= ff.text_field :request_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<div class="flex items-center">
|
<%= ff.label :request_email_body, t('email_body'), class: 'label' %>
|
||||||
<%= ff.label :request_email_body, t('email_body'), class: 'label' %>
|
<%= render 'personalization_settings/markdown_editor', name: ff.field_name(:request_email_body), value: ff.object.request_email_body, variables: AccountConfig::EMAIL_VARIABLES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY] %>
|
||||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<autoresize-textarea>
|
|
||||||
<%= ff.text_area :request_email_body, required: true, class: 'base-input w-full py-2 !rounded-2xl', dir: 'auto' %>
|
|
||||||
</autoresize-textarea>
|
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,38 +45,28 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
</toggle-visible>
|
</toggle-visible>
|
||||||
<%= f.fields_for :preferences do |ff| %>
|
<% @template.submitters.each_with_index do |submitter, index| %>
|
||||||
<% @template.submitters.each_with_index do |submitter, index| %>
|
<div id="request_email_<%= submitter['uuid'] %>" class="<%= 'hidden' if index != 0 %>">
|
||||||
<div id="request_email_<%= submitter['uuid'] %>" class="<%= 'hidden' if index != 0 %>">
|
<% submitter_preferences = f.object.preferences['submitters'].to_a.find { |e| e['uuid'] == submitter['uuid'] } || {} %>
|
||||||
<% submitter_preferences = f.object.preferences['submitters'].to_a.find { |e| e['uuid'] == submitter['uuid'] } || {} %>
|
<% submitter_email_preferences_values = submitter_preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence %>
|
||||||
<% submitter_email_preferences_values = submitter_preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence %>
|
<% submitter_email_values = submitter_email_preferences_values || template_email_preferences_values.presence || default_template_email_preferences_values %>
|
||||||
<%= ff.fields_for :submitters, Struct.new(:request_email_subject, :request_email_body).new(*(submitter_preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || template_email_preferences_values.presence || default_template_email_preferences_values)), index: nil do |fff| %>
|
<%= hidden_field_tag 'template[preferences][submitters][][uuid]', submitter['uuid'] %>
|
||||||
<%= fff.hidden_field :uuid, value: submitter['uuid'] %>
|
<div class="form-control">
|
||||||
<div class="form-control">
|
<div class="flex justify-between">
|
||||||
<div class="flex justify-between">
|
<label class="label"><%= t('email_subject') %></label>
|
||||||
<%= fff.label :request_email_subject, t('email_subject'), class: 'label' %>
|
<% if submitter_email_preferences_values.present? %>
|
||||||
<% if submitter_email_preferences_values.present? %>
|
<label for="submitter_invitation_email_reset_link" class="label underline">
|
||||||
<label for="submitter_invitation_email_reset_link" class="label underline">
|
<%= t('reset_default') %>
|
||||||
<%= t('reset_default') %>
|
</label>
|
||||||
</label>
|
<% end %>
|
||||||
<% end %>
|
</div>
|
||||||
</div>
|
<%= text_field_tag 'template[preferences][submitters][][request_email_subject]', submitter_email_values.first, required: true, class: 'base-input', dir: 'auto', autocomplete: 'off' %>
|
||||||
<%= fff.text_field :request_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
|
||||||
</div>
|
|
||||||
<div class="form-control">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<%= fff.label :request_email_body, t('email_body'), class: 'label' %>
|
|
||||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<autoresize-textarea>
|
|
||||||
<%= fff.text_area :request_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
|
||||||
</autoresize-textarea>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<div class="form-control">
|
||||||
|
<label class="label"><%= t('email_body') %></label>
|
||||||
|
<%= render 'personalization_settings/markdown_editor', name: 'template[preferences][submitters][][request_email_body]', value: submitter_email_values.last, variables: AccountConfig::EMAIL_VARIABLES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY] %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<%= form_for '', url: template_prefillable_fields_path(template), method: :post, data: { close_on_submit: false } do |f| %>
|
<%= form_for '', url: template_prefillable_fields_path(template), method: :post, data: { close_on_submit: false } do |f| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.hidden_field :prefillable, value: 'true' %>
|
<%= f.hidden_field :prefillable, value: 'true' %>
|
||||||
<%= f.label :field_uuid, t(:invite_form_fields), class: 'label' %>
|
<%= f.label :field_uuid, t(:sender_form_fields), class: 'label' %>
|
||||||
<div class="join w-full">
|
<div class="join w-full">
|
||||||
<%= select_tag :field_uuid, options_for_select(select_fields), prompt: t(:select_field), class: 'base-select w-full join-item', dir: 'auto', required: true %>
|
<%= select_tag :field_uuid, options_for_select(select_fields), prompt: t(:select_field), class: 'base-select w-full join-item', dir: 'auto', required: true %>
|
||||||
<%= f.button button_title(title: t('add'), disabled_with: t('add')), class: 'base-button join-item !px-6' %>
|
<%= f.button button_title(title: t('add'), disabled_with: t('add')), class: 'base-button join-item !px-6' %>
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
</label>
|
</label>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="flex gap-2 mt-3">
|
<div class="flex gap-2 mt-3">
|
||||||
<input id="embedding_url" type="text" value="<%= start_form_url(slug: @template.slug) %>" class="base-input w-full" autocomplete="off" readonly>
|
<input id="embedding_url" type="text" value="<%= start_form_url(slug: @template.slug, host: form_link_host) %>" class="base-input w-full" autocomplete="off" readonly>
|
||||||
<check-on-click data-element-id="template_shared_link">
|
<check-on-click data-element-id="template_shared_link">
|
||||||
<%= render 'shared/clipboard_copy', icon: 'copy', text: start_form_url(slug: @template.slug), class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: t('copy'), copied_title: t('copied') %>
|
<%= render 'shared/clipboard_copy', icon: 'copy', text: start_form_url(slug: @template.slug, host: form_link_host), class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: t('copy'), copied_title: t('copied') %>
|
||||||
</check-on-click>
|
</check-on-click>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ 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.euid == 2000
|
if Process.uid.zero?
|
||||||
begin
|
begin
|
||||||
test_file = "#{ENV.fetch('WORKDIR', '.')}/test"
|
test_file = "#{ENV.fetch('WORKDIR', '.')}/test"
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ ActiveSupport.on_load(:active_storage_attachment) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/BlockLength
|
||||||
ActiveSupport.on_load(:active_storage_blob) do
|
ActiveSupport.on_load(:active_storage_blob) do
|
||||||
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
||||||
attribute :io_data, :string, default: ''
|
attribute :io_data, :string, default: ''
|
||||||
@@ -22,6 +23,12 @@ ActiveSupport.on_load(:active_storage_blob) do
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.proxy_path(blob, expires_at: nil, filename: nil)
|
||||||
|
Rails.application.routes.url_helpers.blobs_proxy_path(
|
||||||
|
signed_uuid: blob.signed_uuid(expires_at:), filename: filename || blob.filename
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def uuid
|
def uuid
|
||||||
super || begin
|
super || begin
|
||||||
new_uuid = SecureRandom.uuid
|
new_uuid = SecureRandom.uuid
|
||||||
@@ -40,6 +47,7 @@ ActiveSupport.on_load(:active_storage_blob) do
|
|||||||
service.delete(key)
|
service.delete(key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Metrics/BlockLength
|
||||||
|
|
||||||
ActiveStorage::LogSubscriber.detach_from(:active_storage) if Rails.env.production?
|
ActiveStorage::LogSubscriber.detach_from(:active_storage) if Rails.env.production?
|
||||||
|
|
||||||
|
|||||||
+149
-17
@@ -44,7 +44,7 @@ en: &en
|
|||||||
click_here_to_send_a_reset_password_email_html: '<label class="link" for="resend_password_button">Click here</label> to send a reset password email.'
|
click_here_to_send_a_reset_password_email_html: '<label class="link" for="resend_password_button">Click here</label> to send a reset password email.'
|
||||||
edit_order: Edit Order
|
edit_order: Edit Order
|
||||||
expirable_file_download_links: Expirable file download links
|
expirable_file_download_links: Expirable file download links
|
||||||
invite_form_fields: Invite form fields
|
sender_form_fields: Sender form fields
|
||||||
default_parties: Default parties
|
default_parties: Default parties
|
||||||
authenticate_embedded_form_preview_with_token: Authenticate embedded form preview with token
|
authenticate_embedded_form_preview_with_token: Authenticate embedded form preview with token
|
||||||
stripe_integration: Stripe Integration
|
stripe_integration: Stripe Integration
|
||||||
@@ -218,7 +218,7 @@ en: &en
|
|||||||
copy: Copy
|
copy: Copy
|
||||||
copied: Copied
|
copied: Copied
|
||||||
rotate: Rotate
|
rotate: Rotate
|
||||||
remove_existing_api_token_and_generated_a_new_one_are_you_sure_: Remove existing API token and generated a new one. Are you sure?
|
remove_existing_api_token_and_generated_a_new_one_are_you_sure_: Remove existing API token and generate a new one. Are you sure?
|
||||||
request_signature_multiple_submitters_with_default_values: Request signature, multiple submitters with default values
|
request_signature_multiple_submitters_with_default_values: Request signature, multiple submitters with default values
|
||||||
request_signature_single_submitter: Request signature, single submitter
|
request_signature_single_submitter: Request signature, single submitter
|
||||||
template_details: Template details
|
template_details: Template details
|
||||||
@@ -330,8 +330,8 @@ en: &en
|
|||||||
initials: Initials
|
initials: Initials
|
||||||
update_initials: Update Initials
|
update_initials: Update Initials
|
||||||
unable_to_save_initials: Unable to save initials.
|
unable_to_save_initials: Unable to save initials.
|
||||||
initials_has_been_saved: Initials has been saved.
|
initials_has_been_saved: Initials have been saved.
|
||||||
initials_has_been_removed: Initials has been removed.
|
initials_has_been_removed: Initials have been removed.
|
||||||
change_password: Change Password
|
change_password: Change Password
|
||||||
two_factor_authentication: Two-Factor Authentication
|
two_factor_authentication: Two-Factor Authentication
|
||||||
2fa_is_not_configured: 2FA is not configured
|
2fa_is_not_configured: 2FA is not configured
|
||||||
@@ -388,7 +388,7 @@ en: &en
|
|||||||
from: From
|
from: From
|
||||||
account_sid: Account SID
|
account_sid: Account SID
|
||||||
send_sms_via_webhook: Send SMS via webhook
|
send_sms_via_webhook: Send SMS via webhook
|
||||||
webhook_integration_allows_to_send_sms_using_any_provider: Webhook integration allows to send SMS using any provider
|
webhook_integration_allows_to_send_sms_using_any_provider: Webhook integration allows you to send SMS using any provider
|
||||||
test: Test
|
test: Test
|
||||||
single_sign_on_with_saml_2_0: Single Sign On with SAML 2.0
|
single_sign_on_with_saml_2_0: Single Sign On with SAML 2.0
|
||||||
force_sso_disable_login_with_email_and_password: Force SSO (disable login with email and password)
|
force_sso_disable_login_with_email_and_password: Force SSO (disable login with email and password)
|
||||||
@@ -420,7 +420,7 @@ en: &en
|
|||||||
send_signature_request_emails_without_limits_with_docuseal_pro: Send signature request emails without limits with DocuSeal Pro
|
send_signature_request_emails_without_limits_with_docuseal_pro: Send signature request emails without limits with DocuSeal Pro
|
||||||
count_emails_used: '%{count} emails used'
|
count_emails_used: '%{count} emails used'
|
||||||
has_been_connected: has been connected
|
has_been_connected: has been connected
|
||||||
sms_not_configured: SMS not Configure
|
sms_not_configured: SMS not Configured
|
||||||
configure_sms_settings_in_order_to_send_text_messages_: 'Configure SMS settings in order to send text messages:'
|
configure_sms_settings_in_order_to_send_text_messages_: 'Configure SMS settings in order to send text messages:'
|
||||||
go_to_sms_settings: Go to SMS settings
|
go_to_sms_settings: Go to SMS settings
|
||||||
back_to_active: Back to Active
|
back_to_active: Back to Active
|
||||||
@@ -500,6 +500,7 @@ en: &en
|
|||||||
submission_requester: Submission requester
|
submission_requester: Submission requester
|
||||||
specified_email: Specified email
|
specified_email: Specified email
|
||||||
invite_by_name: 'Invite by %{name}'
|
invite_by_name: 'Invite by %{name}'
|
||||||
|
invite_via_form_field: Invite via Form Field
|
||||||
same_as_name: 'Same as %{name}'
|
same_as_name: 'Same as %{name}'
|
||||||
default_email: Default Email
|
default_email: Default Email
|
||||||
processing: Processing
|
processing: Processing
|
||||||
@@ -596,7 +597,7 @@ en: &en
|
|||||||
upload_file: Upload file
|
upload_file: Upload file
|
||||||
upgrade_your_plan_to_invite_more_users_contact_email: 'Upgrade your plan to invite more users (contact %{email}).'
|
upgrade_your_plan_to_invite_more_users_contact_email: 'Upgrade your plan to invite more users (contact %{email}).'
|
||||||
contact_your_admin_email_to_invite_more_users: 'Contact your admin %{email} to invite more users.'
|
contact_your_admin_email_to_invite_more_users: 'Contact your admin %{email} to invite more users.'
|
||||||
contact_your_administrator_to_add_new_users: Contact your administrator to add new user
|
contact_your_administrator_to_add_new_users: Contact your administrator to add new users
|
||||||
one_hour: 1 hour
|
one_hour: 1 hour
|
||||||
two_hours: 2 hours
|
two_hours: 2 hours
|
||||||
four_hours: 4 hours
|
four_hours: 4 hours
|
||||||
@@ -625,7 +626,7 @@ en: &en
|
|||||||
personalize_email_content: Personalize email content
|
personalize_email_content: Personalize email content
|
||||||
automated_reminders: Automated reminders
|
automated_reminders: Automated reminders
|
||||||
bulk_send_from_spreadsheet: Bulk send from spreadsheet
|
bulk_send_from_spreadsheet: Bulk send from spreadsheet
|
||||||
identify_verification_via_sms: Identify verification via SMS
|
identify_verification_via_sms: Identity verification via SMS
|
||||||
start_with_pro: Start with Pro
|
start_with_pro: Start with Pro
|
||||||
user_month: user / month
|
user_month: user / month
|
||||||
developer_sandbox: Developer Sandbox.
|
developer_sandbox: Developer Sandbox.
|
||||||
@@ -737,7 +738,7 @@ en: &en
|
|||||||
find_suitable_zapier_templates_to_automate_your_workflow: Find suitable Zapier templates to automate your workflow.
|
find_suitable_zapier_templates_to_automate_your_workflow: Find suitable Zapier templates to automate your workflow.
|
||||||
get_started: Get started
|
get_started: Get started
|
||||||
click_here_to_learn_more_about_user_roles_and_permissions_html: '<a href="https://www.docuseal.com/resources/manage-users-and-roles" class="link" rel="noopener noreferrer nofollow" target="_blank">Click here</a> to learn more about user roles and permissions.'
|
click_here_to_learn_more_about_user_roles_and_permissions_html: '<a href="https://www.docuseal.com/resources/manage-users-and-roles" class="link" rel="noopener noreferrer nofollow" target="_blank">Click here</a> to learn more about user roles and permissions.'
|
||||||
count_10_signature_request_emails_sent_this_month_upgrade_to_pro_to_send_unlimited_signature_request_email: '%{count} / 10 signature request emails sent this month. Upgrade to Pro to send unlimited signature request email.'
|
count_10_signature_request_emails_sent_this_month_upgrade_to_pro_to_send_unlimited_signature_request_email: '%{count} / 10 signature request emails sent this month. Upgrade to Pro to send unlimited signature request emails.'
|
||||||
test_mode_emails_limit_will_be_reset_within_24_hours: Test mode emails limit will be reset within 24 hours.
|
test_mode_emails_limit_will_be_reset_within_24_hours: Test mode emails limit will be reset within 24 hours.
|
||||||
on_a_scale_of_1_to_10_how_satisfied_are_you_with_the_docuseal_product_: On a scale of 1 to 10, how satisfied are you with the DocuSeal product?
|
on_a_scale_of_1_to_10_how_satisfied_are_you_with_the_docuseal_product_: On a scale of 1 to 10, how satisfied are you with the DocuSeal product?
|
||||||
tell_us_more_about_your_experience: Tell us more about your experience
|
tell_us_more_about_your_experience: Tell us more about your experience
|
||||||
@@ -755,7 +756,7 @@ en: &en
|
|||||||
manage_plan: Manage plan
|
manage_plan: Manage plan
|
||||||
this_submission_has_multiple_signers_which_prevents_the_use_of_a_sharing_link_html: This submission has multiple signers, which prevents the use of a sharing link as it's unclear which signer is responsible for specific fields. To resolve this, follow this <a href="https://www.docuseal.com/resources/pre-filling-recipients" class="link font-bold" rel="noopener noreferrer nofollow" target="_blank">guide</a> to define the default signer details.
|
this_submission_has_multiple_signers_which_prevents_the_use_of_a_sharing_link_html: This submission has multiple signers, which prevents the use of a sharing link as it's unclear which signer is responsible for specific fields. To resolve this, follow this <a href="https://www.docuseal.com/resources/pre-filling-recipients" class="link font-bold" rel="noopener noreferrer nofollow" target="_blank">guide</a> to define the default signer details.
|
||||||
welcome_to_docuseal: Welcome to DocuSeal
|
welcome_to_docuseal: Welcome to DocuSeal
|
||||||
start_a_quick_tour_to_learn_how_to_create_an_send_your_first_document: Start a quick tour to learn how to create an send your first document
|
start_a_quick_tour_to_learn_how_to_create_an_send_your_first_document: Start a quick tour to learn how to create and send your first document
|
||||||
start_tour: Start Tour
|
start_tour: Start Tour
|
||||||
name_a_z: Name A-Z
|
name_a_z: Name A-Z
|
||||||
recently_used: Recently used
|
recently_used: Recently used
|
||||||
@@ -815,7 +816,7 @@ en: &en
|
|||||||
connect_gmail_or_outlook: Connect Gmail or Outlook
|
connect_gmail_or_outlook: Connect Gmail or Outlook
|
||||||
connect_your_email_to_bulk_send: Connect your email to bulk send
|
connect_your_email_to_bulk_send: Connect your email to bulk send
|
||||||
connect_your_email_or_outlook_account_or_add_smtp_settings_to_bulk_send: Connect your Gmail or Outlook account or add SMTP settings to bulk send.
|
connect_your_email_or_outlook_account_or_add_smtp_settings_to_bulk_send: Connect your Gmail or Outlook account or add SMTP settings to bulk send.
|
||||||
are_you_sure_you_want_to_add_recipients_without_sending_to_send_emails_it_requires_to_connect_gmail_or_outlook: Are you sure you want to add recipients without sending? To send emails it requires to connect Gmail or Outlook.
|
are_you_sure_you_want_to_add_recipients_without_sending_to_send_emails_it_requires_to_connect_gmail_or_outlook: Are you sure you want to add recipients without sending? To send emails you need to connect Gmail or Outlook.
|
||||||
template_name_has_been_completed_by_submitters_html: '"<strong>{template.name}</strong>" has been completed by <strong>{submission.submitters}</strong>'
|
template_name_has_been_completed_by_submitters_html: '"<strong>{template.name}</strong>" has been completed by <strong>{submission.submitters}</strong>'
|
||||||
please_check_the_copy_of_your_template_name_in_the_email_attachments_html: 'Please check the copy of your "<strong>{template.name}</strong>" in the email attachments.'
|
please_check_the_copy_of_your_template_name_in_the_email_attachments_html: 'Please check the copy of your "<strong>{template.name}</strong>" in the email attachments.'
|
||||||
you_have_been_invited_to_sign_the_template_name_html: 'You have been invited to sign the "<strong>{template.name}</strong>".'
|
you_have_been_invited_to_sign_the_template_name_html: 'You have been invited to sign the "<strong>{template.name}</strong>".'
|
||||||
@@ -886,6 +887,13 @@ en: &en
|
|||||||
if_you_didnt_request_this_you_can_ignore_this_email: "If you didn't request this, please ignore this email."
|
if_you_didnt_request_this_you_can_ignore_this_email: "If you didn't request this, please ignore this email."
|
||||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Your password won't change until you open the link above and set a new one."
|
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Your password won't change until you open the link above and set a new one."
|
||||||
too_many_requests_try_again_later: Too many requests, try again later.
|
too_many_requests_try_again_later: Too many requests, try again later.
|
||||||
|
bold: Bold
|
||||||
|
italic: Italic
|
||||||
|
underline: Underline
|
||||||
|
undo: Undo
|
||||||
|
redo: Redo
|
||||||
|
add_variable: Add variable
|
||||||
|
enter_a_url_or_variable_name: Enter a URL or variable name
|
||||||
devise:
|
devise:
|
||||||
confirmations:
|
confirmations:
|
||||||
confirmed: Your email address has been successfully confirmed.
|
confirmed: Your email address has been successfully confirmed.
|
||||||
@@ -1002,6 +1010,16 @@ en: &en
|
|||||||
events:
|
events:
|
||||||
range_with_total: "%{from}-%{to} of %{count} events"
|
range_with_total: "%{from}-%{to} of %{count} events"
|
||||||
range_without_total: "%{from}-%{to} events"
|
range_without_total: "%{from}-%{to} events"
|
||||||
|
variables:
|
||||||
|
account_name: Account name
|
||||||
|
submitter_link: Submitter link
|
||||||
|
template_name: Template name
|
||||||
|
submission_submitters: Submitters list
|
||||||
|
submission_link: Submission link
|
||||||
|
documents_link: Documents link
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%B %d, %Y %H:%M:%S"
|
||||||
|
|
||||||
es: &es
|
es: &es
|
||||||
knowledge_based_authentication: Autenticación basada en el conocimiento
|
knowledge_based_authentication: Autenticación basada en el conocimiento
|
||||||
@@ -1022,7 +1040,7 @@ es: &es
|
|||||||
party: Parte
|
party: Parte
|
||||||
edit_order: Edita Pedido
|
edit_order: Edita Pedido
|
||||||
select: Seleccionar
|
select: Seleccionar
|
||||||
invite_form_fields: Invitar campos del formulario
|
sender_form_fields: Campos del formulario del remitente
|
||||||
pro: Pro
|
pro: Pro
|
||||||
default_parties: Partes predeterminadas
|
default_parties: Partes predeterminadas
|
||||||
authenticate_embedded_form_preview_with_token: Autenticar vista previa del formulario incrustado con token
|
authenticate_embedded_form_preview_with_token: Autenticar vista previa del formulario incrustado con token
|
||||||
@@ -1487,6 +1505,7 @@ es: &es
|
|||||||
submission_requester: Solicitante del envío
|
submission_requester: Solicitante del envío
|
||||||
specified_email: Correo electrónico especificado
|
specified_email: Correo electrónico especificado
|
||||||
invite_by_name: 'Invitar por %{name}'
|
invite_by_name: 'Invitar por %{name}'
|
||||||
|
invite_via_form_field: Invitar a través de campo del formulario
|
||||||
same_as_name: 'Igual que %{name}'
|
same_as_name: 'Igual que %{name}'
|
||||||
default_email: Correo electrónico predeterminado
|
default_email: Correo electrónico predeterminado
|
||||||
processing: Procesando
|
processing: Procesando
|
||||||
@@ -1870,6 +1889,13 @@ es: &es
|
|||||||
if_you_didnt_request_this_you_can_ignore_this_email: "Si no solicitaste esto, puedes ignorar este correo electrónico."
|
if_you_didnt_request_this_you_can_ignore_this_email: "Si no solicitaste esto, puedes ignorar este correo electrónico."
|
||||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Tu contraseña no cambiará hasta que abras el enlace anterior y establezcas una nueva."
|
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Tu contraseña no cambiará hasta que abras el enlace anterior y establezcas una nueva."
|
||||||
too_many_requests_try_again_later: Demasiadas solicitudes. Intenta de nuevo más tarde.
|
too_many_requests_try_again_later: Demasiadas solicitudes. Intenta de nuevo más tarde.
|
||||||
|
bold: Negrita
|
||||||
|
italic: Cursiva
|
||||||
|
underline: Subrayado
|
||||||
|
undo: Deshacer
|
||||||
|
redo: Rehacer
|
||||||
|
add_variable: Agregar variable
|
||||||
|
enter_a_url_or_variable_name: Ingrese una URL o nombre de variable
|
||||||
devise:
|
devise:
|
||||||
confirmations:
|
confirmations:
|
||||||
confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente.
|
confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente.
|
||||||
@@ -1986,6 +2012,16 @@ es: &es
|
|||||||
events:
|
events:
|
||||||
range_with_total: "%{from}-%{to} de %{count} eventos"
|
range_with_total: "%{from}-%{to} de %{count} eventos"
|
||||||
range_without_total: "%{from}-%{to} eventos"
|
range_without_total: "%{from}-%{to} eventos"
|
||||||
|
variables:
|
||||||
|
account_name: Nombre de la cuenta
|
||||||
|
submitter_link: Enlace del firmante
|
||||||
|
template_name: Nombre de la plantilla
|
||||||
|
submission_submitters: Lista de firmantes
|
||||||
|
submission_link: Enlace del envío
|
||||||
|
documents_link: Enlace de los documentos
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%-d de %B de %Y %H:%M:%S"
|
||||||
|
|
||||||
it: &it
|
it: &it
|
||||||
knowledge_based_authentication: Autenticazione basata sulla conoscenza
|
knowledge_based_authentication: Autenticazione basata sulla conoscenza
|
||||||
@@ -2006,7 +2042,7 @@ it: &it
|
|||||||
party: Parte
|
party: Parte
|
||||||
edit_order: Modifica Ordine
|
edit_order: Modifica Ordine
|
||||||
select: Seleziona
|
select: Seleziona
|
||||||
invite_form_fields: Invita campi modulo
|
sender_form_fields: Campi del modulo del mittente
|
||||||
pro: Pro
|
pro: Pro
|
||||||
default_parties: Parti predefiniti
|
default_parties: Parti predefiniti
|
||||||
authenticate_embedded_form_preview_with_token: "Autentica l'anteprima del modulo incorporato con il token"
|
authenticate_embedded_form_preview_with_token: "Autentica l'anteprima del modulo incorporato con il token"
|
||||||
@@ -2471,6 +2507,7 @@ it: &it
|
|||||||
submission_requester: "Richiedente dell'invio"
|
submission_requester: "Richiedente dell'invio"
|
||||||
specified_email: Email specificata
|
specified_email: Email specificata
|
||||||
invite_by_name: 'Invito da %{name}'
|
invite_by_name: 'Invito da %{name}'
|
||||||
|
invite_via_form_field: Invito tramite campo del modulo
|
||||||
same_as_name: 'Uguale a %{name}'
|
same_as_name: 'Uguale a %{name}'
|
||||||
default_email: Email predefinita
|
default_email: Email predefinita
|
||||||
processing: Elaborazione in corso
|
processing: Elaborazione in corso
|
||||||
@@ -2855,6 +2892,13 @@ it: &it
|
|||||||
if_you_didnt_request_this_you_can_ignore_this_email: "Se non hai richiesto questo, puoi ignorare questa email."
|
if_you_didnt_request_this_you_can_ignore_this_email: "Se non hai richiesto questo, puoi ignorare questa email."
|
||||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "La tua password non cambierà finché non apri il link sopra e ne imposti una nuova."
|
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "La tua password non cambierà finché non apri il link sopra e ne imposti una nuova."
|
||||||
too_many_requests_try_again_later: Troppe richieste. Riprova più tardi.
|
too_many_requests_try_again_later: Troppe richieste. Riprova più tardi.
|
||||||
|
bold: Grassetto
|
||||||
|
italic: Corsivo
|
||||||
|
underline: Sottolineato
|
||||||
|
undo: Annulla
|
||||||
|
redo: Ripeti
|
||||||
|
add_variable: Aggiungi variabile
|
||||||
|
enter_a_url_or_variable_name: Inserisci un URL o nome variabile
|
||||||
devise:
|
devise:
|
||||||
confirmations:
|
confirmations:
|
||||||
confirmed: Il tuo indirizzo email è stato confermato con successo.
|
confirmed: Il tuo indirizzo email è stato confermato con successo.
|
||||||
@@ -2971,6 +3015,16 @@ it: &it
|
|||||||
events:
|
events:
|
||||||
range_with_total: "%{from}-%{to} di %{count} eventi"
|
range_with_total: "%{from}-%{to} di %{count} eventi"
|
||||||
range_without_total: "%{from}-%{to} eventi"
|
range_without_total: "%{from}-%{to} eventi"
|
||||||
|
variables:
|
||||||
|
account_name: Nome dell'account
|
||||||
|
submitter_link: Link del firmatario
|
||||||
|
template_name: Nome del modello
|
||||||
|
submission_submitters: Lista dei firmatari
|
||||||
|
submission_link: Link dell'invio
|
||||||
|
documents_link: Link dei documenti
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%d %B %Y %H:%M:%S"
|
||||||
|
|
||||||
fr: &fr
|
fr: &fr
|
||||||
knowledge_based_authentication: Authentification basée sur la connaissance
|
knowledge_based_authentication: Authentification basée sur la connaissance
|
||||||
@@ -2991,7 +3045,7 @@ fr: &fr
|
|||||||
party: Partie
|
party: Partie
|
||||||
edit_order: Modifier l’ordre
|
edit_order: Modifier l’ordre
|
||||||
select: Sélectionner
|
select: Sélectionner
|
||||||
invite_form_fields: Champs du formulaire d’invitation
|
sender_form_fields: Champs du formulaire de l’expéditeur
|
||||||
pro: Pro
|
pro: Pro
|
||||||
default_parties: Parties par défaut
|
default_parties: Parties par défaut
|
||||||
authenticate_embedded_form_preview_with_token: Authentifier l’aperçu du formulaire intégré avec un jeton
|
authenticate_embedded_form_preview_with_token: Authentifier l’aperçu du formulaire intégré avec un jeton
|
||||||
@@ -3456,6 +3510,7 @@ fr: &fr
|
|||||||
submission_requester: Demandeur de soumission
|
submission_requester: Demandeur de soumission
|
||||||
specified_email: E‑mail spécifié
|
specified_email: E‑mail spécifié
|
||||||
invite_by_name: Inviter par %{name}
|
invite_by_name: Inviter par %{name}
|
||||||
|
invite_via_form_field: Inviter via champ du formulaire
|
||||||
same_as_name: Identique à %{name}
|
same_as_name: Identique à %{name}
|
||||||
default_email: E‑mail par défaut
|
default_email: E‑mail par défaut
|
||||||
processing: Traitement en cours
|
processing: Traitement en cours
|
||||||
@@ -3836,6 +3891,13 @@ fr: &fr
|
|||||||
if_you_didnt_request_this_you_can_ignore_this_email: "Si vous n'avez pas fait cette demande, veuillez ignorer cet e-mail."
|
if_you_didnt_request_this_you_can_ignore_this_email: "Si vous n'avez pas fait cette demande, veuillez ignorer cet e-mail."
|
||||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Votre mot de passe ne changera pas tant que vous n’aurez pas ouvert le lien ci-dessus et défini un nouveau mot de passe."
|
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Votre mot de passe ne changera pas tant que vous n’aurez pas ouvert le lien ci-dessus et défini un nouveau mot de passe."
|
||||||
too_many_requests_try_again_later: Trop de demandes. Réessayez plus tard.
|
too_many_requests_try_again_later: Trop de demandes. Réessayez plus tard.
|
||||||
|
bold: Gras
|
||||||
|
italic: Italique
|
||||||
|
underline: Souligné
|
||||||
|
undo: Annuler
|
||||||
|
redo: Rétablir
|
||||||
|
add_variable: Ajouter une variable
|
||||||
|
enter_a_url_or_variable_name: Entrez une URL ou un nom de variable
|
||||||
devise:
|
devise:
|
||||||
confirmations:
|
confirmations:
|
||||||
confirmed: Votre adresse e-mail a été confirmée avec succès.
|
confirmed: Votre adresse e-mail a été confirmée avec succès.
|
||||||
@@ -3952,6 +4014,16 @@ fr: &fr
|
|||||||
events:
|
events:
|
||||||
range_with_total: "%{from}-%{to} sur %{count} événements"
|
range_with_total: "%{from}-%{to} sur %{count} événements"
|
||||||
range_without_total: "%{from}-%{to} événements"
|
range_without_total: "%{from}-%{to} événements"
|
||||||
|
variables:
|
||||||
|
account_name: Nom du compte
|
||||||
|
submitter_link: Lien du signataire
|
||||||
|
template_name: Nom du modèle
|
||||||
|
submission_submitters: Liste des signataires
|
||||||
|
submission_link: Lien de la soumission
|
||||||
|
documents_link: Lien des documents
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%A %d %B %Y %Hh%Mm%Ss"
|
||||||
|
|
||||||
pt: &pt
|
pt: &pt
|
||||||
knowledge_based_authentication: Autenticação baseada em conhecimento
|
knowledge_based_authentication: Autenticação baseada em conhecimento
|
||||||
@@ -3972,7 +4044,7 @@ pt: &pt
|
|||||||
party: Parte
|
party: Parte
|
||||||
edit_order: Edita Pedido
|
edit_order: Edita Pedido
|
||||||
select: Selecionar
|
select: Selecionar
|
||||||
invite_form_fields: Convidar campos do formulário
|
sender_form_fields: Campos do formulário do remetente
|
||||||
pro: Pro
|
pro: Pro
|
||||||
default_parties: Partes padrão
|
default_parties: Partes padrão
|
||||||
authenticate_embedded_form_preview_with_token: Autenticar visualização incorporada do formulário com token
|
authenticate_embedded_form_preview_with_token: Autenticar visualização incorporada do formulário com token
|
||||||
@@ -4437,6 +4509,7 @@ pt: &pt
|
|||||||
submission_requester: Solicitante de submissão
|
submission_requester: Solicitante de submissão
|
||||||
specified_email: E-mail especificado
|
specified_email: E-mail especificado
|
||||||
invite_by_name: 'Convidado por %{name}'
|
invite_by_name: 'Convidado por %{name}'
|
||||||
|
invite_via_form_field: Convidar via campo do formulário
|
||||||
same_as_name: 'Igual a %{name}'
|
same_as_name: 'Igual a %{name}'
|
||||||
default_email: E-mail padrão
|
default_email: E-mail padrão
|
||||||
processing: Processando
|
processing: Processando
|
||||||
@@ -4820,6 +4893,13 @@ pt: &pt
|
|||||||
if_you_didnt_request_this_you_can_ignore_this_email: "Se você não solicitou isso, pode ignorar este e-mail."
|
if_you_didnt_request_this_you_can_ignore_this_email: "Se você não solicitou isso, pode ignorar este e-mail."
|
||||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Sua senha não será alterada até que você abra o link acima e defina uma nova."
|
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Sua senha não será alterada até que você abra o link acima e defina uma nova."
|
||||||
too_many_requests_try_again_later: Muitas solicitações. Tente novamente mais tarde.
|
too_many_requests_try_again_later: Muitas solicitações. Tente novamente mais tarde.
|
||||||
|
bold: Negrito
|
||||||
|
italic: Itálico
|
||||||
|
underline: Sublinhado
|
||||||
|
undo: Desfazer
|
||||||
|
redo: Refazer
|
||||||
|
add_variable: Adicionar variável
|
||||||
|
enter_a_url_or_variable_name: Digite uma URL ou nome de variável
|
||||||
devise:
|
devise:
|
||||||
confirmations:
|
confirmations:
|
||||||
confirmed: Seu endereço de e-mail foi confirmado com sucesso.
|
confirmed: Seu endereço de e-mail foi confirmado com sucesso.
|
||||||
@@ -4936,6 +5016,16 @@ pt: &pt
|
|||||||
events:
|
events:
|
||||||
range_with_total: "%{from}-%{to} de %{count} eventos"
|
range_with_total: "%{from}-%{to} de %{count} eventos"
|
||||||
range_without_total: "%{from}-%{to} eventos"
|
range_without_total: "%{from}-%{to} eventos"
|
||||||
|
variables:
|
||||||
|
account_name: Nome da conta
|
||||||
|
submitter_link: Link do signatário
|
||||||
|
template_name: Nome do modelo
|
||||||
|
submission_submitters: Lista de signatários
|
||||||
|
submission_link: Link da submissão
|
||||||
|
documents_link: Link dos documentos
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%A, %d de %B de %Y, %H:%M:%Sh"
|
||||||
|
|
||||||
de: &de
|
de: &de
|
||||||
knowledge_based_authentication: Wissensbasierte Authentifizierung
|
knowledge_based_authentication: Wissensbasierte Authentifizierung
|
||||||
@@ -4965,7 +5055,7 @@ de: &de
|
|||||||
click_here_to_send_a_reset_password_email_html: '<label class="link" for="resend_password_button">Klicken Sie hier</label>, um eine E-Mail zum Zurücksetzen des Passworts zu senden.'
|
click_here_to_send_a_reset_password_email_html: '<label class="link" for="resend_password_button">Klicken Sie hier</label>, um eine E-Mail zum Zurücksetzen des Passworts zu senden.'
|
||||||
edit_order: Bestellung bearbeiten
|
edit_order: Bestellung bearbeiten
|
||||||
expirable_file_download_links: Ablaufbare Datei-Download-Links
|
expirable_file_download_links: Ablaufbare Datei-Download-Links
|
||||||
invite_form_fields: Einladungsformular-Felder
|
sender_form_fields: Absenderformular-Felder
|
||||||
default_parties: Standardparteien
|
default_parties: Standardparteien
|
||||||
authenticate_embedded_form_preview_with_token: Eingebettete Formularvorschau mit Token authentifizieren
|
authenticate_embedded_form_preview_with_token: Eingebettete Formularvorschau mit Token authentifizieren
|
||||||
stripe_integration: Stripe-Integration
|
stripe_integration: Stripe-Integration
|
||||||
@@ -5421,6 +5511,7 @@ de: &de
|
|||||||
submission_requester: Anfragende Person
|
submission_requester: Anfragende Person
|
||||||
specified_email: Angegebene E-Mail
|
specified_email: Angegebene E-Mail
|
||||||
invite_by_name: 'Einladung von %{name}'
|
invite_by_name: 'Einladung von %{name}'
|
||||||
|
invite_via_form_field: Einladung über Formularfeld
|
||||||
same_as_name: 'Gleich wie %{name}'
|
same_as_name: 'Gleich wie %{name}'
|
||||||
default_email: Standard-E-Mail
|
default_email: Standard-E-Mail
|
||||||
processing: Verarbeitung
|
processing: Verarbeitung
|
||||||
@@ -5804,6 +5895,13 @@ de: &de
|
|||||||
if_you_didnt_request_this_you_can_ignore_this_email: "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren."
|
if_you_didnt_request_this_you_can_ignore_this_email: "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren."
|
||||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Ihr Passwort wird erst geändert, wenn Sie den obigen Link öffnen und ein neues festlegen."
|
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Ihr Passwort wird erst geändert, wenn Sie den obigen Link öffnen und ein neues festlegen."
|
||||||
too_many_requests_try_again_later: Zu viele Anfragen. Versuchen Sie es später erneut.
|
too_many_requests_try_again_later: Zu viele Anfragen. Versuchen Sie es später erneut.
|
||||||
|
bold: Fett
|
||||||
|
italic: Kursiv
|
||||||
|
underline: Unterstrichen
|
||||||
|
undo: Rückgängig
|
||||||
|
redo: Wiederholen
|
||||||
|
add_variable: Variable hinzufügen
|
||||||
|
enter_a_url_or_variable_name: Geben Sie eine URL oder einen Variablennamen ein
|
||||||
devise:
|
devise:
|
||||||
confirmations:
|
confirmations:
|
||||||
confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt.
|
confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt.
|
||||||
@@ -5920,6 +6018,16 @@ de: &de
|
|||||||
events:
|
events:
|
||||||
range_with_total: "%{from}-%{to} von %{count} Ereignissen"
|
range_with_total: "%{from}-%{to} von %{count} Ereignissen"
|
||||||
range_without_total: "%{from}-%{to} Ereignisse"
|
range_without_total: "%{from}-%{to} Ereignisse"
|
||||||
|
variables:
|
||||||
|
account_name: Kontoname
|
||||||
|
submitter_link: Link des Unterzeichners
|
||||||
|
template_name: Vorlagenname
|
||||||
|
submission_submitters: Liste der Unterzeichner
|
||||||
|
submission_link: Link der Einreichung
|
||||||
|
documents_link: Link der Dokumente
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%A, %d. %B %Y, %H:%M:%S Uhr"
|
||||||
|
|
||||||
pl:
|
pl:
|
||||||
require_phone_2fa_to_open: Wymagaj uwierzytelniania telefonicznego 2FA do otwarcia
|
require_phone_2fa_to_open: Wymagaj uwierzytelniania telefonicznego 2FA do otwarcia
|
||||||
@@ -6337,7 +6445,7 @@ nl: &nl
|
|||||||
click_here_to_send_a_reset_password_email_html: <label class="link" for="resend_password_button">Klik hier</label> om een e-mail voor wachtwoordherstel te verzenden.
|
click_here_to_send_a_reset_password_email_html: <label class="link" for="resend_password_button">Klik hier</label> om een e-mail voor wachtwoordherstel te verzenden.
|
||||||
edit_order: Volgorde bewerken
|
edit_order: Volgorde bewerken
|
||||||
expirable_file_download_links: Verlopende downloadlinks voor bestanden
|
expirable_file_download_links: Verlopende downloadlinks voor bestanden
|
||||||
invite_form_fields: Velden van uitnodigingsformulier
|
sender_form_fields: Velden van afzenderformulier
|
||||||
default_parties: Standaard partijen
|
default_parties: Standaard partijen
|
||||||
authenticate_embedded_form_preview_with_token: Preview van ingesloten formulier authenticeren met token
|
authenticate_embedded_form_preview_with_token: Preview van ingesloten formulier authenticeren met token
|
||||||
stripe_integration: Stripe-integratie
|
stripe_integration: Stripe-integratie
|
||||||
@@ -6794,6 +6902,7 @@ nl: &nl
|
|||||||
submission_requester: Aanvrager van inzending
|
submission_requester: Aanvrager van inzending
|
||||||
specified_email: Opgegeven e-mail
|
specified_email: Opgegeven e-mail
|
||||||
invite_by_name: Uitnodigen door %{name}
|
invite_by_name: Uitnodigen door %{name}
|
||||||
|
invite_via_form_field: Uitnodigen via formulierveld
|
||||||
same_as_name: Zelfde als %{name}
|
same_as_name: Zelfde als %{name}
|
||||||
default_email: Standaard e-mail
|
default_email: Standaard e-mail
|
||||||
processing: Verwerken
|
processing: Verwerken
|
||||||
@@ -7173,6 +7282,13 @@ nl: &nl
|
|||||||
if_you_didnt_request_this_you_can_ignore_this_email: "Als je dit niet hebt aangevraagd, kun je deze e-mail negeren."
|
if_you_didnt_request_this_you_can_ignore_this_email: "Als je dit niet hebt aangevraagd, kun je deze e-mail negeren."
|
||||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Je wachtwoord wordt niet gewijzigd totdat je de bovenstaande link opent en een nieuw wachtwoord instelt."
|
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Je wachtwoord wordt niet gewijzigd totdat je de bovenstaande link opent en een nieuw wachtwoord instelt."
|
||||||
too_many_requests_try_again_later: Te veel verzoeken. Probeer het later opnieuw.
|
too_many_requests_try_again_later: Te veel verzoeken. Probeer het later opnieuw.
|
||||||
|
bold: Vet
|
||||||
|
italic: Cursief
|
||||||
|
underline: Onderstreept
|
||||||
|
undo: Ongedaan maken
|
||||||
|
redo: Opnieuw
|
||||||
|
add_variable: Variabele toevoegen
|
||||||
|
enter_a_url_or_variable_name: Voer een URL of variabelenaam in
|
||||||
devise:
|
devise:
|
||||||
confirmations:
|
confirmations:
|
||||||
confirmed: Je e-mailadres is succesvol bevestigd.
|
confirmed: Je e-mailadres is succesvol bevestigd.
|
||||||
@@ -7289,6 +7405,16 @@ nl: &nl
|
|||||||
events:
|
events:
|
||||||
range_with_total: "%{from}-%{to} van %{count} gebeurtenissen"
|
range_with_total: "%{from}-%{to} van %{count} gebeurtenissen"
|
||||||
range_without_total: "%{from}-%{to} gebeurtenissen"
|
range_without_total: "%{from}-%{to} gebeurtenissen"
|
||||||
|
variables:
|
||||||
|
account_name: Accountnaam
|
||||||
|
submitter_link: Link van de ondertekenaar
|
||||||
|
template_name: Sjabloonnaam
|
||||||
|
submission_submitters: Lijst van ondertekenaars
|
||||||
|
submission_link: Link van de inzending
|
||||||
|
documents_link: Link van de documenten
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%d %B %Y %H:%M:%S"
|
||||||
|
|
||||||
ar:
|
ar:
|
||||||
require_phone_2fa_to_open: "تطلب فتح عبر تحقق الهاتف ذو العاملين"
|
require_phone_2fa_to_open: "تطلب فتح عبر تحقق الهاتف ذو العاملين"
|
||||||
@@ -7586,12 +7712,18 @@ en-US:
|
|||||||
date:
|
date:
|
||||||
formats:
|
formats:
|
||||||
default: "%m/%d/%Y"
|
default: "%m/%d/%Y"
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%B %d, %Y %I:%M:%S %p"
|
||||||
|
|
||||||
en-GB:
|
en-GB:
|
||||||
<<: *en
|
<<: *en
|
||||||
date:
|
date:
|
||||||
formats:
|
formats:
|
||||||
default: "%d/%m/%Y"
|
default: "%d/%m/%Y"
|
||||||
|
time:
|
||||||
|
formats:
|
||||||
|
detailed: "%d %B, %Y %H:%M:%S"
|
||||||
|
|
||||||
es-ES:
|
es-ES:
|
||||||
<<: *es
|
<<: *es
|
||||||
|
|||||||
@@ -29,7 +29,12 @@ module LoadActiveStorageConfigs
|
|||||||
|
|
||||||
service_configurations = ActiveSupport::ConfigurationFile.parse(STORAGE_YML_PATH)
|
service_configurations = ActiveSupport::ConfigurationFile.parse(STORAGE_YML_PATH)
|
||||||
service_configurations[service].merge!(configs) if configs.present?
|
service_configurations[service].merge!(configs) if configs.present?
|
||||||
service_configurations[service][:force_path_style] = true if configs&.dig('endpoint').present?
|
if configs&.dig('endpoint').present?
|
||||||
|
service_configurations[service][:force_path_style] = true
|
||||||
|
if configs['endpoint'].include?('cloudflarestorage.com')
|
||||||
|
service_configurations[service][:request_checksum_calculation] = 'when_required'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if service == 'google'
|
if service == 'google'
|
||||||
service_configurations[service][:credentials] = JSON.parse(configs.fetch('credentials', '{}'))
|
service_configurations[service][:credentials] = JSON.parse(configs.fetch('credentials', '{}'))
|
||||||
|
|||||||
+124
-5
@@ -1,13 +1,132 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module MarkdownToHtml
|
module MarkdownToHtml
|
||||||
LINK_REGEXP = %r{\[([^\]]+)\]\((https?://[^)]+)\)}
|
TAGS = {
|
||||||
|
'' => %w[<em> </em>],
|
||||||
|
'*' => %w[<strong> </strong>],
|
||||||
|
'~' => %w[<s> </s>]
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
INLINE_TOKENIZER = /(\[)|(\]\(([^)]+?)\))|(?:`([^`].*?)`)|(\*\*\*|\*\*|\*|~~)/
|
||||||
|
|
||||||
|
ALLOWED_TAGS = %w[p br strong b em i u a].freeze
|
||||||
|
ALLOWED_ATTRIBUTES = %w[href].freeze
|
||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
def call(text)
|
def call(markdown)
|
||||||
text.gsub(LINK_REGEXP) do
|
return '' if markdown.blank?
|
||||||
ApplicationController.helpers.link_to(Regexp.last_match(1), Regexp.last_match(2))
|
|
||||||
end
|
text = auto_link_urls(markdown)
|
||||||
|
html = render_markdown(text)
|
||||||
|
|
||||||
|
ActionController::Base.helpers.sanitize(html, tags: ALLOWED_TAGS, attributes: ALLOWED_ATTRIBUTES)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
BRACKETS = { ')' => '(', ']' => '[', '}' => '{' }.freeze
|
||||||
|
|
||||||
|
def auto_link_urls(text)
|
||||||
|
link_parts = text.split(%r{((?:https?://|www\.)[^\s<>\u00A0"]+)})
|
||||||
|
|
||||||
|
link_parts.map.with_index do |part, index|
|
||||||
|
if part.match?(%r{\A(?:https?://|www\.)}) && !(index > 0 && link_parts[index - 1]&.match?(/\]\(\s*\z/))
|
||||||
|
url_part = part.dup
|
||||||
|
punctuation = []
|
||||||
|
|
||||||
|
while url_part.sub!(%r{[^\p{Word}/\-=;]\z}, '')
|
||||||
|
punctuation.push(::Regexp.last_match(0))
|
||||||
|
|
||||||
|
opening = BRACKETS[punctuation.last]
|
||||||
|
|
||||||
|
next unless opening && url_part.count(opening) > url_part.count(punctuation.last)
|
||||||
|
|
||||||
|
url_part << punctuation.pop
|
||||||
|
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
trail = punctuation.reverse.join
|
||||||
|
url = url_part.start_with?('www.') ? "https://#{url_part}" : url_part
|
||||||
|
|
||||||
|
"[#{url_part}](#{url})#{trail}"
|
||||||
|
else
|
||||||
|
part
|
||||||
|
end
|
||||||
|
end.join
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_markdown(text)
|
||||||
|
text = text.gsub(/\+\+([^+]+)\+\+/, '<u>\1</u>')
|
||||||
|
|
||||||
|
paragraphs = text.split(/\n{2,}/)
|
||||||
|
|
||||||
|
html = paragraphs.filter_map do |para|
|
||||||
|
content = para.strip
|
||||||
|
|
||||||
|
next if content.empty?
|
||||||
|
|
||||||
|
next '<p><br></p>' if [' ', '&nbsp;'].include?(content)
|
||||||
|
|
||||||
|
content = content.gsub(/ *\n/, '<br>')
|
||||||
|
|
||||||
|
"<p>#{parse_inline(content)}</p>"
|
||||||
|
end.join
|
||||||
|
|
||||||
|
html.presence || '<p></p>'
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics
|
||||||
|
def parse_inline(text)
|
||||||
|
context = []
|
||||||
|
out = ''
|
||||||
|
last = 0
|
||||||
|
|
||||||
|
tag = lambda do |t|
|
||||||
|
desc = TAGS[t[1] || '']
|
||||||
|
|
||||||
|
return t unless desc
|
||||||
|
|
||||||
|
is_end = context.last == t
|
||||||
|
is_end ? context.pop : context.push(t)
|
||||||
|
desc[is_end ? 1 : 0]
|
||||||
|
end
|
||||||
|
|
||||||
|
flush = lambda do
|
||||||
|
str = ''
|
||||||
|
str += tag.call(context.last) while context.any?
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
while last <= text.length && (m = INLINE_TOKENIZER.match(text, last))
|
||||||
|
prev = text[last...m.begin(0)]
|
||||||
|
last = m.end(0)
|
||||||
|
chunk = m[0]
|
||||||
|
|
||||||
|
if m[4]
|
||||||
|
chunk = "<code>#{ERB::Util.html_escape(m[4])}</code>"
|
||||||
|
elsif m[2]
|
||||||
|
out = out.sub(/\A(.*)<a>/m, "\\1<a href=\"#{ERB::Util.html_escape(m[3])}\">")
|
||||||
|
out = out.gsub('<a>', '[')
|
||||||
|
chunk = "#{flush.call}</a>"
|
||||||
|
elsif m[1]
|
||||||
|
chunk = '<a>'
|
||||||
|
elsif m[5]
|
||||||
|
chunk =
|
||||||
|
if m[5] == '***'
|
||||||
|
if context.include?('*') && context.include?('**')
|
||||||
|
tag.call('*') + tag.call('**')
|
||||||
|
else
|
||||||
|
tag.call('**') + tag.call('*')
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tag.call(m[5])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
out += prev.to_s + chunk
|
||||||
|
end
|
||||||
|
|
||||||
|
(out + text[last..].to_s + flush.call).gsub('<a>', '[')
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -89,8 +89,10 @@ module ReplaceEmailVariables
|
|||||||
# rubocop:enable Metrics
|
# rubocop:enable Metrics
|
||||||
|
|
||||||
def build_documents_links_text(submitter, sig = nil)
|
def build_documents_links_text(submitter, sig = nil)
|
||||||
|
url_options = build_url_options_for(submitter)
|
||||||
|
|
||||||
Rails.application.routes.url_helpers.submissions_preview_url(
|
Rails.application.routes.url_helpers.submissions_preview_url(
|
||||||
submitter.submission.slug, { sig:, **Docuseal.default_url_options }.compact
|
submitter.submission.slug, { sig:, **url_options }.compact
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -139,14 +141,9 @@ module ReplaceEmailVariables
|
|||||||
end
|
end
|
||||||
|
|
||||||
def build_submitter_link(submitter, tracking_event_type)
|
def build_submitter_link(submitter, tracking_event_type)
|
||||||
if tracking_event_type == 'click_email'
|
url_options = build_url_options_for(submitter, is_email: tracking_event_type == 'click_email')
|
||||||
url_options =
|
|
||||||
if EMAIL_HOST.present?
|
|
||||||
{ host: EMAIL_HOST, protocol: ENV['FORCE_SSL'].present? ? 'https' : 'http' }
|
|
||||||
else
|
|
||||||
Docuseal.default_url_options
|
|
||||||
end
|
|
||||||
|
|
||||||
|
if tracking_event_type == 'click_email'
|
||||||
Rails.application.routes.url_helpers.submit_form_url(
|
Rails.application.routes.url_helpers.submit_form_url(
|
||||||
slug: submitter.slug,
|
slug: submitter.slug,
|
||||||
t: SubmissionEvents.build_tracking_param(submitter, 'click_email'),
|
t: SubmissionEvents.build_tracking_param(submitter, 'click_email'),
|
||||||
@@ -156,11 +153,22 @@ module ReplaceEmailVariables
|
|||||||
Rails.application.routes.url_helpers.submit_form_url(
|
Rails.application.routes.url_helpers.submit_form_url(
|
||||||
slug: submitter.slug,
|
slug: submitter.slug,
|
||||||
c: SubmissionEvents.build_tracking_param(submitter, 'click_sms'),
|
c: SubmissionEvents.build_tracking_param(submitter, 'click_sms'),
|
||||||
**Docuseal.default_url_options
|
**url_options
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_url_options_for(submitter, is_email: true)
|
||||||
|
if Docuseal.multitenant? &&
|
||||||
|
(config = AccountConfig.find_by(account_id: submitter.account_id, key: :custom_domain))
|
||||||
|
{ host: config.value, protocol: 'https' }
|
||||||
|
elsif is_email && EMAIL_HOST.present?
|
||||||
|
{ host: EMAIL_HOST, protocol: ENV['FORCE_SSL'].present? ? 'https' : 'http' }
|
||||||
|
else
|
||||||
|
Docuseal.default_url_options
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def build_submission_link(submission)
|
def build_submission_link(submission)
|
||||||
Rails.application.routes.url_helpers.submission_url(submission, **Docuseal.default_url_options)
|
Rails.application.routes.url_helpers.submission_url(submission, **Docuseal.default_url_options)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ module Submissions
|
|||||||
template_submitter = template_submitters.find { |e| e['uuid'] == uuid }
|
template_submitter = template_submitters.find { |e| e['uuid'] == uuid }
|
||||||
end
|
end
|
||||||
|
|
||||||
template_submitter = template_submitter.except('optional_invite_by_uuid', 'invite_by_uuid')
|
template_submitter = template_submitter.except('optional_invite_by_uuid', 'invite_by_uuid',
|
||||||
|
'invite_via_field_uuid')
|
||||||
|
|
||||||
template_submitter['order'] = submitter_attrs['order'] if submitter_attrs['order'].present?
|
template_submitter['order'] = submitter_attrs['order'] if submitter_attrs['order'].present?
|
||||||
|
|
||||||
submission.template_submitters << template_submitter
|
submission.template_submitters << template_submitter
|
||||||
@@ -113,7 +115,10 @@ module Submissions
|
|||||||
item = item.merge('invite_by_uuid' => invite_by_uuid) if invite_by_uuid
|
item = item.merge('invite_by_uuid' => invite_by_uuid) if invite_by_uuid
|
||||||
end
|
end
|
||||||
|
|
||||||
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? &&
|
||||||
|
item['invite_via_field_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?
|
item = item.merge('order' => submitter_attr['order']) if submitter_attr && submitter_attr['order'].present?
|
||||||
|
|||||||
@@ -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_TIMESTAMP_SECONDS_KEY,
|
||||||
AccountConfig::WITH_AUDIT_SENDER_KEY,
|
AccountConfig::WITH_AUDIT_SENDER_KEY,
|
||||||
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY])
|
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY])
|
||||||
|
|
||||||
@@ -126,6 +127,7 @@ module Submissions
|
|||||||
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_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
|
||||||
|
with_timestamp_seconds = configs.find { |c| c.key == AccountConfig::WITH_TIMESTAMP_SECONDS_KEY }&.value == true
|
||||||
|
|
||||||
timezone = account.timezone
|
timezone = account.timezone
|
||||||
timezone = last_submitter.timezone || account.timezone if with_submitter_timezone
|
timezone = last_submitter.timezone || account.timezone if with_submitter_timezone
|
||||||
@@ -489,8 +491,10 @@ module Submissions
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
time_format = with_timestamp_seconds ? :detailed : :long
|
||||||
|
|
||||||
[
|
[
|
||||||
"#{I18n.l(event.event_timestamp.in_time_zone(timezone), format: :long, locale: account.locale)} " \
|
"#{I18n.l(event.event_timestamp.in_time_zone(timezone), format: time_format, locale: account.locale)} " \
|
||||||
"#{TimeUtils.timezone_abbr(timezone, event.event_timestamp)}",
|
"#{TimeUtils.timezone_abbr(timezone, event.event_timestamp)}",
|
||||||
composer.document.layout.formatted_text_box(text_box)
|
composer.document.layout.formatted_text_box(text_box)
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ module Submissions
|
|||||||
configs = submission.account.account_configs.where(key: [AccountConfig::FLATTEN_RESULT_PDF_KEY,
|
configs = submission.account.account_configs.where(key: [AccountConfig::FLATTEN_RESULT_PDF_KEY,
|
||||||
AccountConfig::WITH_SIGNATURE_ID,
|
AccountConfig::WITH_SIGNATURE_ID,
|
||||||
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY,
|
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY,
|
||||||
|
AccountConfig::WITH_TIMESTAMP_SECONDS_KEY,
|
||||||
AccountConfig::WITH_FILE_LINKS_KEY,
|
AccountConfig::WITH_FILE_LINKS_KEY,
|
||||||
AccountConfig::WITH_SIGNATURE_ID_REASON_KEY])
|
AccountConfig::WITH_SIGNATURE_ID_REASON_KEY])
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ module Submissions
|
|||||||
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
|
||||||
is_flatten = configs.find { |c| c.key == AccountConfig::FLATTEN_RESULT_PDF_KEY }&.value != false
|
is_flatten = configs.find { |c| c.key == AccountConfig::FLATTEN_RESULT_PDF_KEY }&.value != false
|
||||||
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
|
||||||
|
with_timestamp_seconds = configs.find { |c| c.key == AccountConfig::WITH_TIMESTAMP_SECONDS_KEY }&.value == true
|
||||||
with_signature_id_reason =
|
with_signature_id_reason =
|
||||||
configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false
|
configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ module Submissions
|
|||||||
GenerateResultAttachments.fill_submitter_fields(s, submission.account, pdfs_index,
|
GenerateResultAttachments.fill_submitter_fields(s, submission.account, pdfs_index,
|
||||||
with_signature_id:, is_flatten:, with_headings: index.zero?,
|
with_signature_id:, is_flatten:, with_headings: index.zero?,
|
||||||
with_submitter_timezone:, with_file_links:,
|
with_submitter_timezone:, with_file_links:,
|
||||||
with_signature_id_reason:)
|
with_signature_id_reason:, with_timestamp_seconds:)
|
||||||
end
|
end
|
||||||
|
|
||||||
template = submission.template
|
template = submission.template
|
||||||
|
|||||||
@@ -140,11 +140,13 @@ module Submissions
|
|||||||
configs = submitter.account.account_configs.where(key: [AccountConfig::FLATTEN_RESULT_PDF_KEY,
|
configs = submitter.account.account_configs.where(key: [AccountConfig::FLATTEN_RESULT_PDF_KEY,
|
||||||
AccountConfig::WITH_SIGNATURE_ID,
|
AccountConfig::WITH_SIGNATURE_ID,
|
||||||
AccountConfig::WITH_FILE_LINKS_KEY,
|
AccountConfig::WITH_FILE_LINKS_KEY,
|
||||||
|
AccountConfig::WITH_TIMESTAMP_SECONDS_KEY,
|
||||||
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY,
|
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY,
|
||||||
AccountConfig::WITH_SIGNATURE_ID_REASON_KEY])
|
AccountConfig::WITH_SIGNATURE_ID_REASON_KEY])
|
||||||
|
|
||||||
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
|
||||||
is_flatten = configs.find { |c| c.key == AccountConfig::FLATTEN_RESULT_PDF_KEY }&.value != false
|
is_flatten = configs.find { |c| c.key == AccountConfig::FLATTEN_RESULT_PDF_KEY }&.value != false
|
||||||
|
with_timestamp_seconds = configs.find { |c| c.key == AccountConfig::WITH_TIMESTAMP_SECONDS_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
|
||||||
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_signature_id_reason =
|
with_signature_id_reason =
|
||||||
@@ -195,11 +197,13 @@ module Submissions
|
|||||||
fill_submitter_fields(submitter, submitter.account, pdfs_index, with_signature_id:, is_flatten:,
|
fill_submitter_fields(submitter, submitter.account, pdfs_index, with_signature_id:, is_flatten:,
|
||||||
with_submitter_timezone:,
|
with_submitter_timezone:,
|
||||||
with_file_links:,
|
with_file_links:,
|
||||||
|
with_timestamp_seconds:,
|
||||||
with_signature_id_reason:)
|
with_signature_id_reason:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fill_submitter_fields(submitter, account, pdfs_index, with_signature_id:, is_flatten:, with_headings: nil,
|
def fill_submitter_fields(submitter, account, pdfs_index, with_signature_id:, is_flatten:, with_headings: nil,
|
||||||
with_submitter_timezone: false, with_signature_id_reason: true, with_file_links: nil)
|
with_submitter_timezone: false, with_signature_id_reason: true,
|
||||||
|
with_timestamp_seconds: false, with_file_links: nil)
|
||||||
cell_layouters = Hash.new do |hash, valign|
|
cell_layouters = Hash.new do |hash, valign|
|
||||||
hash[valign] = HexaPDF::Layout::TextLayouter.new(text_valign: valign.to_sym, text_align: :center)
|
hash[valign] = HexaPDF::Layout::TextLayouter.new(text_valign: valign.to_sym, text_align: :center)
|
||||||
end
|
end
|
||||||
@@ -320,13 +324,15 @@ module Submissions
|
|||||||
timezone = submitter.account.timezone
|
timezone = submitter.account.timezone
|
||||||
timezone = submitter.timezone || submitter.account.timezone if with_submitter_timezone
|
timezone = submitter.timezone || submitter.account.timezone if with_submitter_timezone
|
||||||
|
|
||||||
|
time_format = with_timestamp_seconds ? :detailed : :long
|
||||||
|
|
||||||
if with_signature_id_reason || field.dig('preferences', 'reasons').present?
|
if with_signature_id_reason || field.dig('preferences', 'reasons').present?
|
||||||
"#{"#{I18n.t('reason')}: " if reason_value}#{reason_value || I18n.t('digitally_signed_by')} " \
|
"#{"#{I18n.t('reason')}: " if reason_value}#{reason_value || I18n.t('digitally_signed_by')} " \
|
||||||
"#{submitter.name}#{" <#{submitter.email}>" if submitter.email.present?}\n" \
|
"#{submitter.name}#{" <#{submitter.email}>" if submitter.email.present?}\n" \
|
||||||
"#{I18n.l(attachment.created_at.in_time_zone(timezone), format: :long)} " \
|
"#{I18n.l(attachment.created_at.in_time_zone(timezone), format: time_format)} " \
|
||||||
"#{TimeUtils.timezone_abbr(timezone, attachment.created_at)}"
|
"#{TimeUtils.timezone_abbr(timezone, attachment.created_at)}"
|
||||||
else
|
else
|
||||||
"#{I18n.l(attachment.created_at.in_time_zone(timezone), format: :long)} " \
|
"#{I18n.l(attachment.created_at.in_time_zone(timezone), format: time_format)} " \
|
||||||
"#{TimeUtils.timezone_abbr(timezone, attachment.created_at)}"
|
"#{TimeUtils.timezone_abbr(timezone, attachment.created_at)}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -569,7 +575,11 @@ module Submissions
|
|||||||
fill_color:,
|
fill_color:,
|
||||||
font_size:)
|
font_size:)
|
||||||
|
|
||||||
line_height = layouter.fit([text], cell_width, height).lines.first.height
|
line = layouter.fit([text], width, height).lines.first
|
||||||
|
|
||||||
|
line_height = line.height
|
||||||
|
|
||||||
|
cell_width = [line.width, cell_width].max
|
||||||
|
|
||||||
if preferences_font_size.blank? && line_height > (area['h'] * height)
|
if preferences_font_size.blank? && line_height > (area['h'] * height)
|
||||||
text = HexaPDF::Layout::TextFragment.create(char,
|
text = HexaPDF::Layout::TextFragment.create(char,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ module Submitters
|
|||||||
AccountConfig::ALLOW_TO_PARTIAL_DOWNLOAD_KEY,
|
AccountConfig::ALLOW_TO_PARTIAL_DOWNLOAD_KEY,
|
||||||
AccountConfig::ALLOW_TYPED_SIGNATURE,
|
AccountConfig::ALLOW_TYPED_SIGNATURE,
|
||||||
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY,
|
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY,
|
||||||
|
AccountConfig::WITH_TIMESTAMP_SECONDS_KEY,
|
||||||
AccountConfig::WITH_SIGNATURE_ID_REASON_KEY,
|
AccountConfig::WITH_SIGNATURE_ID_REASON_KEY,
|
||||||
*(Docuseal.multitenant? ? [] : [AccountConfig::POLICY_LINKS_KEY])].freeze
|
*(Docuseal.multitenant? ? [] : [AccountConfig::POLICY_LINKS_KEY])].freeze
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ module Submitters
|
|||||||
require_signing_reason = find_safe_value(configs, AccountConfig::REQUIRE_SIGNING_REASON_KEY) == true
|
require_signing_reason = find_safe_value(configs, AccountConfig::REQUIRE_SIGNING_REASON_KEY) == true
|
||||||
enforce_signing_order = find_safe_value(configs, AccountConfig::ENFORCE_SIGNING_ORDER_KEY) == true
|
enforce_signing_order = find_safe_value(configs, AccountConfig::ENFORCE_SIGNING_ORDER_KEY) == true
|
||||||
with_submitter_timezone = find_safe_value(configs, AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY) == true
|
with_submitter_timezone = find_safe_value(configs, AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY) == true
|
||||||
|
with_timestamp_seconds = find_safe_value(configs, AccountConfig::WITH_TIMESTAMP_SECONDS_KEY) == true
|
||||||
with_signature_id_reason = find_safe_value(configs, AccountConfig::WITH_SIGNATURE_ID_REASON_KEY) != false
|
with_signature_id_reason = find_safe_value(configs, AccountConfig::WITH_SIGNATURE_ID_REASON_KEY) != false
|
||||||
with_field_labels = find_safe_value(configs, AccountConfig::WITH_FIELD_LABELS_KEY) != false
|
with_field_labels = find_safe_value(configs, AccountConfig::WITH_FIELD_LABELS_KEY) != false
|
||||||
policy_links = find_safe_value(configs, AccountConfig::POLICY_LINKS_KEY)
|
policy_links = find_safe_value(configs, AccountConfig::POLICY_LINKS_KEY)
|
||||||
@@ -43,7 +45,7 @@ module Submitters
|
|||||||
reuse_signature:, with_decline:, with_partial_download:,
|
reuse_signature:, with_decline:, with_partial_download:,
|
||||||
policy_links:, enforce_signing_order:, completed_message:,
|
policy_links:, enforce_signing_order:, completed_message:,
|
||||||
require_signing_reason:, prefill_signature:, with_submitter_timezone:,
|
require_signing_reason:, prefill_signature:, with_submitter_timezone:,
|
||||||
with_signature_id_reason:, with_signature_id:, with_field_labels: }
|
with_signature_id_reason:, with_signature_id:, with_field_labels:, with_timestamp_seconds: }
|
||||||
|
|
||||||
keys.each do |key|
|
keys.each do |key|
|
||||||
attrs[key.to_sym] = configs.find { |e| e.key == key.to_s }&.value
|
attrs[key.to_sym] = configs.find { |e| e.key == key.to_s }&.value
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ module Submitters
|
|||||||
RequiredFieldError = Class.new(StandardError)
|
RequiredFieldError = Class.new(StandardError)
|
||||||
|
|
||||||
VARIABLE_REGEXP = /\{\{?(\w+)\}\}?/
|
VARIABLE_REGEXP = /\{\{?(\w+)\}\}?/
|
||||||
|
PHONE_REGEXP = /[+\d()\s-]+/
|
||||||
NONEDITABLE_FIELD_TYPES = %w[stamp heading strikethrough].freeze
|
NONEDITABLE_FIELD_TYPES = %w[stamp heading strikethrough].freeze
|
||||||
|
|
||||||
STRFTIME_MAP = {
|
STRFTIME_MAP = {
|
||||||
@@ -45,14 +46,18 @@ module Submitters
|
|||||||
assign_completed_attributes(submitter, request, validate_required:) if params[:completed] == 'true'
|
assign_completed_attributes(submitter, request, validate_required:) if params[:completed] == 'true'
|
||||||
|
|
||||||
ApplicationRecord.transaction do
|
ApplicationRecord.transaction do
|
||||||
maybe_set_signature_reason!(values, submitter, params)
|
reason_field = maybe_set_signature_reason!(values, submitter, params)
|
||||||
validate_values!(values, submitter, params, request)
|
validate_values!(reason_field ? values.except(reason_field['uuid']) : values, submitter, params, request)
|
||||||
|
|
||||||
if (touch_attachment_uuid = params[:touch_attachment_uuid].presence)
|
if (touch_attachment_uuid = params[:touch_attachment_uuid].presence)
|
||||||
ActiveStorage::Attachment.where(uuid: touch_attachment_uuid, record: submitter).touch_all(:created_at)
|
ActiveStorage::Attachment.where(uuid: touch_attachment_uuid, record: submitter).touch_all(:created_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
SubmissionEvents.create_with_tracking_data(submitter, 'complete_form', request) if params[:completed] == 'true'
|
if params[:completed] == 'true'
|
||||||
|
maybe_invite_via_field(submitter, request)
|
||||||
|
|
||||||
|
SubmissionEvents.create_with_tracking_data(submitter, 'complete_form', request)
|
||||||
|
end
|
||||||
|
|
||||||
submitter.save!
|
submitter.save!
|
||||||
end
|
end
|
||||||
@@ -107,7 +112,9 @@ module Submitters
|
|||||||
signature_field['preferences'] ||= {}
|
signature_field['preferences'] ||= {}
|
||||||
signature_field['preferences']['reason_field_uuid'] = reason_field_uuid
|
signature_field['preferences']['reason_field_uuid'] = reason_field_uuid
|
||||||
|
|
||||||
unless submitter.submission.template_fields.find { |e| e['uuid'] == reason_field_uuid }
|
reason_field = submitter.submission.template_fields.find { |e| e['uuid'] == reason_field_uuid }
|
||||||
|
|
||||||
|
unless reason_field
|
||||||
reason_field = { 'type' => 'text',
|
reason_field = { 'type' => 'text',
|
||||||
'uuid' => reason_field_uuid,
|
'uuid' => reason_field_uuid,
|
||||||
'name' => I18n.t(:reason),
|
'name' => I18n.t(:reason),
|
||||||
@@ -119,6 +126,8 @@ module Submitters
|
|||||||
end
|
end
|
||||||
|
|
||||||
submitter.submission.save!
|
submitter.submission.save!
|
||||||
|
|
||||||
|
reason_field
|
||||||
end
|
end
|
||||||
|
|
||||||
def normalized_values(params)
|
def normalized_values(params)
|
||||||
@@ -403,7 +412,54 @@ module Submitters
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_value!(_value, _field, _params, _submitter, _request)
|
def maybe_invite_via_field(submitter, request)
|
||||||
|
submission = submitter.submission
|
||||||
|
|
||||||
|
is_invited = false
|
||||||
|
|
||||||
|
submission.template_submitters.each do |s|
|
||||||
|
field_uuid = s['invite_via_field_uuid']
|
||||||
|
|
||||||
|
next if field_uuid.blank?
|
||||||
|
|
||||||
|
field = submission.template_fields.find { |e| e['uuid'] == field_uuid }
|
||||||
|
|
||||||
|
next unless field
|
||||||
|
next unless field['submitter_uuid'] == submitter.uuid
|
||||||
|
|
||||||
|
next if submission.submitters.exists?(uuid: s['uuid'])
|
||||||
|
|
||||||
|
value = submitter.values[field_uuid]
|
||||||
|
|
||||||
|
next if value.blank?
|
||||||
|
|
||||||
|
if value.include?('@')
|
||||||
|
email = Submissions.normalize_email(value)
|
||||||
|
elsif value.match?(PHONE_REGEXP)
|
||||||
|
phone = value.gsub(/[^+\d]/, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
next if email.blank? && phone.blank?
|
||||||
|
|
||||||
|
submission.submitters.create!(uuid: s['uuid'], email:, phone:, account_id: submitter.account_id)
|
||||||
|
|
||||||
|
SubmissionEvents.create_with_tracking_data(submitter, 'invite_party', request, { uuid: submitter.uuid })
|
||||||
|
|
||||||
|
is_invited = true
|
||||||
|
end
|
||||||
|
|
||||||
|
submission.update!(submitters_order: :preserved) if is_invited
|
||||||
|
|
||||||
|
submitter
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_value!(_value, field, _params, submitter, _request)
|
||||||
|
if field['readonly'] == true
|
||||||
|
Rollbar.warning("Readonly field #{submitter.id}: #{field['uuid']}") if defined?(Rollbar)
|
||||||
|
|
||||||
|
raise ValidationError, 'Read-only field'
|
||||||
|
end
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ module Templates
|
|||||||
def filter_undefined_submitters(template_submitters)
|
def filter_undefined_submitters(template_submitters)
|
||||||
template_submitters.to_a.select do |item|
|
template_submitters.to_a.select do |item|
|
||||||
item['invite_by_uuid'].blank? && item['optional_invite_by_uuid'].blank? &&
|
item['invite_by_uuid'].blank? && item['optional_invite_by_uuid'].blank? &&
|
||||||
|
item['invite_via_field_uuid'].blank? &&
|
||||||
item['linked_to_uuid'].blank? && item['is_requester'].blank? && item['email'].blank?
|
item['linked_to_uuid'].blank? && item['is_requester'].blank? && item['email'].blank?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+20
-16
@@ -4,7 +4,7 @@ module Templates
|
|||||||
module Clone
|
module Clone
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
# rubocop:disable Metrics, Style/CombinableLoops
|
# rubocop:disable Metrics
|
||||||
def call(original_template, author:, external_id: nil, name: nil, folder_name: nil)
|
def call(original_template, author:, external_id: nil, name: nil, folder_name: nil)
|
||||||
template = original_template.account.templates.new
|
template = original_template.account.templates.new
|
||||||
|
|
||||||
@@ -49,20 +49,6 @@ module Templates
|
|||||||
submitter['uuid'] = new_submitter_uuid
|
submitter['uuid'] = new_submitter_uuid
|
||||||
end
|
end
|
||||||
|
|
||||||
cloned_submitters.each do |submitter|
|
|
||||||
if submitter['optional_invite_by_uuid'].present?
|
|
||||||
submitter['optional_invite_by_uuid'] = submitter_uuids_replacements[submitter['optional_invite_by_uuid']]
|
|
||||||
end
|
|
||||||
|
|
||||||
if submitter['invite_by_uuid'].present?
|
|
||||||
submitter['invite_by_uuid'] = submitter_uuids_replacements[submitter['invite_by_uuid']]
|
|
||||||
end
|
|
||||||
|
|
||||||
if submitter['linked_to_uuid'].present?
|
|
||||||
submitter['linked_to_uuid'] = submitter_uuids_replacements[submitter['linked_to_uuid']]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
cloned_preferences['submitters'].to_a.each do |submitter|
|
cloned_preferences['submitters'].to_a.each do |submitter|
|
||||||
submitter['uuid'] = submitter_uuids_replacements[submitter['uuid']]
|
submitter['uuid'] = submitter_uuids_replacements[submitter['uuid']]
|
||||||
end
|
end
|
||||||
@@ -97,8 +83,26 @@ module Templates
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
cloned_submitters.each do |submitter|
|
||||||
|
if submitter['optional_invite_by_uuid'].present?
|
||||||
|
submitter['optional_invite_by_uuid'] = submitter_uuids_replacements[submitter['optional_invite_by_uuid']]
|
||||||
|
end
|
||||||
|
|
||||||
|
if submitter['invite_by_uuid'].present?
|
||||||
|
submitter['invite_by_uuid'] = submitter_uuids_replacements[submitter['invite_by_uuid']]
|
||||||
|
end
|
||||||
|
|
||||||
|
if submitter['linked_to_uuid'].present?
|
||||||
|
submitter['linked_to_uuid'] = submitter_uuids_replacements[submitter['linked_to_uuid']]
|
||||||
|
end
|
||||||
|
|
||||||
|
if submitter['invite_via_field_uuid'].present?
|
||||||
|
submitter['invite_via_field_uuid'] = field_uuids_replacements[submitter['invite_via_field_uuid']]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
[cloned_submitters, cloned_fields, cloned_schema, cloned_preferences]
|
[cloned_submitters, cloned_fields, cloned_schema, cloned_preferences]
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics, Style/CombinableLoops
|
# rubocop:enable Metrics
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ module Templates
|
|||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
ANNOTATIONS_SIZE_LIMIT = 6.megabytes
|
ANNOTATIONS_SIZE_LIMIT = 6.megabytes
|
||||||
|
MAX_ZIP_SIZE = 100.megabytes
|
||||||
InvalidFileType = Class.new(StandardError)
|
InvalidFileType = Class.new(StandardError)
|
||||||
PdfEncrypted = Class.new(StandardError)
|
PdfEncrypted = Class.new(StandardError)
|
||||||
|
|
||||||
@@ -72,9 +73,15 @@ module Templates
|
|||||||
|
|
||||||
Array.wrap(files).each do |file|
|
Array.wrap(files).each do |file|
|
||||||
if file.content_type == ZIP_CONTENT_TYPE || file.content_type == X_ZIP_CONTENT_TYPE
|
if file.content_type == ZIP_CONTENT_TYPE || file.content_type == X_ZIP_CONTENT_TYPE
|
||||||
|
total_size = 0
|
||||||
|
|
||||||
Zip::File.open(file.tempfile).each do |entry|
|
Zip::File.open(file.tempfile).each do |entry|
|
||||||
next if entry.directory?
|
next if entry.directory?
|
||||||
|
|
||||||
|
total_size += entry.size
|
||||||
|
|
||||||
|
raise InvalidFileType, 'zip_too_large' if total_size > MAX_ZIP_SIZE
|
||||||
|
|
||||||
tempfile = Tempfile.new(entry.name)
|
tempfile = Tempfile.new(entry.name)
|
||||||
tempfile.binmode
|
tempfile.binmode
|
||||||
entry.get_input_stream { |in_stream| IO.copy_stream(in_stream, tempfile) }
|
entry.get_input_stream { |in_stream| IO.copy_stream(in_stream, tempfile) }
|
||||||
|
|||||||
@@ -14,6 +14,18 @@
|
|||||||
"@hotwired/turbo-rails": "^7.3.0",
|
"@hotwired/turbo-rails": "^7.3.0",
|
||||||
"@specious/htmlflow": "^1.1.0",
|
"@specious/htmlflow": "^1.1.0",
|
||||||
"@tabler/icons-vue": "^2.47.0",
|
"@tabler/icons-vue": "^2.47.0",
|
||||||
|
"@tiptap/core": "^3.19.0",
|
||||||
|
"@tiptap/extension-bold": "^3.19.0",
|
||||||
|
"@tiptap/extension-document": "^3.19.0",
|
||||||
|
"@tiptap/extension-hard-break": "^3.19.0",
|
||||||
|
"@tiptap/extension-italic": "^3.19.0",
|
||||||
|
"@tiptap/extension-link": "^3.19.0",
|
||||||
|
"@tiptap/extension-paragraph": "^3.19.0",
|
||||||
|
"@tiptap/extension-text": "^3.19.0",
|
||||||
|
"@tiptap/extension-underline": "^3.19.0",
|
||||||
|
"@tiptap/extensions": "^3.19.0",
|
||||||
|
"@tiptap/markdown": "^3.19.0",
|
||||||
|
"@tiptap/pm": "^3.19.0",
|
||||||
"autocompleter": "^9.1.0",
|
"autocompleter": "^9.1.0",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"babel-loader": "9.1.2",
|
"babel-loader": "9.1.2",
|
||||||
|
|||||||
@@ -626,6 +626,34 @@ RSpec.describe 'Signing Form' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the signature step with signing reason' do
|
||||||
|
let(:template) { create(:template, account:, author:, only_field_types: %w[signature]) }
|
||||||
|
let(:submission) { create(:submission, template:) }
|
||||||
|
let(:submitter) do
|
||||||
|
create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:account_config, account:, key: AccountConfig::REQUIRE_SIGNING_REASON_KEY, value: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'completes the form with signing reason selected' do
|
||||||
|
visit submit_form_path(slug: submitter.slug)
|
||||||
|
|
||||||
|
find('#expand_form_button').click
|
||||||
|
draw_canvas
|
||||||
|
select 'Approved'
|
||||||
|
click_button 'Sign and Complete'
|
||||||
|
|
||||||
|
expect(page).to have_content('Document has been signed!')
|
||||||
|
|
||||||
|
submitter.reload
|
||||||
|
|
||||||
|
expect(submitter.completed_at).to be_present
|
||||||
|
expect(field_value(submitter, 'Signature')).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when the number step' do
|
context 'when the number step' do
|
||||||
let(:template) { create(:template, account:, author:, only_field_types: %w[number]) }
|
let(:template) { create(:template, account:, author:, only_field_types: %w[number]) }
|
||||||
let(:submission) { create(:submission, template:) }
|
let(:submission) { create(:submission, template:) }
|
||||||
|
|||||||
@@ -1743,6 +1743,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.0.4.tgz#70a3ca56809f7aaabb80af2f9c01ae51e1a8ed41"
|
resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.0.4.tgz#70a3ca56809f7aaabb80af2f9c01ae51e1a8ed41"
|
||||||
integrity sha512-tz4oM+Zn9CYsvtyicsa/AwzKZKL+ITHWkhiu7x+xF77clh2b4Rm+s6xnOgY/sGDWoFWZmtKsE95hxBPkgQQNnQ==
|
integrity sha512-tz4oM+Zn9CYsvtyicsa/AwzKZKL+ITHWkhiu7x+xF77clh2b4Rm+s6xnOgY/sGDWoFWZmtKsE95hxBPkgQQNnQ==
|
||||||
|
|
||||||
|
"@remirror/core-constants@3.0.0":
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@remirror/core-constants/-/core-constants-3.0.0.tgz#96fdb89d25c62e7b6a5d08caf0ce5114370e3b8f"
|
||||||
|
integrity sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==
|
||||||
|
|
||||||
"@sinclair/typebox@^0.25.16":
|
"@sinclair/typebox@^0.25.16":
|
||||||
version "0.25.24"
|
version "0.25.24"
|
||||||
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718"
|
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718"
|
||||||
@@ -1767,6 +1772,89 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-2.47.0.tgz#c41c680d1947e3ab2d60af3febc4132287c60596"
|
resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-2.47.0.tgz#c41c680d1947e3ab2d60af3febc4132287c60596"
|
||||||
integrity sha512-4w5evLh+7FUUiA1GucvGj2ReX2TvOjEr4ejXdwL/bsjoSkof6r1gQmzqI+VHrE2CpJpB3al7bCTulOkFa/RcyA==
|
integrity sha512-4w5evLh+7FUUiA1GucvGj2ReX2TvOjEr4ejXdwL/bsjoSkof6r1gQmzqI+VHrE2CpJpB3al7bCTulOkFa/RcyA==
|
||||||
|
|
||||||
|
"@tiptap/core@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-3.19.0.tgz#dca483b50e1b8a596f695aecde387a79fe7da717"
|
||||||
|
integrity sha512-bpqELwPW+DG8gWiD8iiFtSl4vIBooG5uVJod92Qxn3rA9nFatyXRr4kNbMJmOZ66ezUvmCjXVe/5/G4i5cyzKA==
|
||||||
|
|
||||||
|
"@tiptap/extension-bold@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-3.19.0.tgz#ef0ddfd9b242ef9c25e3348aef9bf2dc681cdc19"
|
||||||
|
integrity sha512-UZgb1d0XK4J/JRIZ7jW+s4S6KjuEDT2z1PPM6ugcgofgJkWQvRZelCPbmtSFd3kwsD+zr9UPVgTh9YIuGQ8t+Q==
|
||||||
|
|
||||||
|
"@tiptap/extension-document@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-3.19.0.tgz#dfa6889cff748d489e0bc1028918bf4571372ba5"
|
||||||
|
integrity sha512-AOf0kHKSFO0ymjVgYSYDncRXTITdTcrj1tqxVazrmO60KNl1Rc2dAggDvIVTEBy5NvceF0scc7q3sE/5ZtVV7A==
|
||||||
|
|
||||||
|
"@tiptap/extension-hard-break@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-3.19.0.tgz#7120524cec9ed4b957963693cb4c57cbecbaecf8"
|
||||||
|
integrity sha512-lAmQraYhPS5hafvCl74xDB5+bLuNwBKIEsVoim35I0sDJj5nTrfhaZgMJ91VamMvT+6FF5f1dvBlxBxAWa8jew==
|
||||||
|
|
||||||
|
"@tiptap/extension-italic@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-3.19.0.tgz#af2a9c095ec846e379041f3e17e1dd101a5a4bf8"
|
||||||
|
integrity sha512-6GffxOnS/tWyCbDkirWNZITiXRta9wrCmrfa4rh+v32wfaOL1RRQNyqo9qN6Wjyl1R42Js+yXTzTTzZsOaLMYA==
|
||||||
|
|
||||||
|
"@tiptap/extension-link@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-3.19.0.tgz#e8e656735bda6ca1d4b6577821e06274ab0ff6c8"
|
||||||
|
integrity sha512-HEGDJnnCPfr7KWu7Dsq+eRRe/mBCsv6DuI+7fhOCLDJjjKzNgrX2abbo/zG3D/4lCVFaVb+qawgJubgqXR/Smw==
|
||||||
|
dependencies:
|
||||||
|
linkifyjs "^4.3.2"
|
||||||
|
|
||||||
|
"@tiptap/extension-paragraph@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-3.19.0.tgz#91adde189aabf13a2bfbb2d961833d3bc2bc055f"
|
||||||
|
integrity sha512-xWa6gj82l5+AzdYyrSk9P4ynySaDzg/SlR1FarXE5yPXibYzpS95IWaVR0m2Qaz7Rrk+IiYOTGxGRxcHLOelNg==
|
||||||
|
|
||||||
|
"@tiptap/extension-text@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.19.0.tgz#353278c97bd8f5bdc29f06942fbd1e856bdb5b18"
|
||||||
|
integrity sha512-K95+SnbZy0h6hNFtfy23n8t/nOcTFEf69In9TSFVVmwn/Nwlke+IfiESAkqbt1/7sKJeegRXYO7WzFEmFl9Q/g==
|
||||||
|
|
||||||
|
"@tiptap/extension-underline@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-3.19.0.tgz#bbc81d085725981d256127ab416f91d0802ec2a4"
|
||||||
|
integrity sha512-800MGEWfG49j10wQzAFiW/ele1HT04MamcL8iyuPNu7ZbjbGN2yknvdrJlRy7hZlzIrVkZMr/1tz62KN33VHIw==
|
||||||
|
|
||||||
|
"@tiptap/extensions@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extensions/-/extensions-3.19.0.tgz#5747c0ebf460b9669e8b4362561872448f66abfe"
|
||||||
|
integrity sha512-ZmGUhLbMWaGqnJh2Bry+6V4M6gMpUDYo4D1xNux5Gng/E/eYtc+PMxMZ/6F7tNTAuujLBOQKj6D+4SsSm457jw==
|
||||||
|
|
||||||
|
"@tiptap/markdown@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/markdown/-/markdown-3.19.0.tgz#dd05451b40f2a553cab0fdbb4a8714a2b2430b5c"
|
||||||
|
integrity sha512-Pnfacq2FHky1rqwmGwEmUJxuZu8VZ8XjaJIqsQC34S3CQWiOU+PukC9In2odzcooiVncLWT9s97jKuYpbmF1tQ==
|
||||||
|
dependencies:
|
||||||
|
marked "^17.0.1"
|
||||||
|
|
||||||
|
"@tiptap/pm@^3.19.0":
|
||||||
|
version "3.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-3.19.0.tgz#5cb499c7b2603ec6550d0c7a70b924f27fdb7692"
|
||||||
|
integrity sha512-789zcnM4a8OWzvbD2DL31d0wbSm9BVeO/R7PLQwLIGysDI3qzrcclyZ8yhqOEVuvPitRRwYLq+mY14jz7kY4cw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-changeset "^2.3.0"
|
||||||
|
prosemirror-collab "^1.3.1"
|
||||||
|
prosemirror-commands "^1.6.2"
|
||||||
|
prosemirror-dropcursor "^1.8.1"
|
||||||
|
prosemirror-gapcursor "^1.3.2"
|
||||||
|
prosemirror-history "^1.4.1"
|
||||||
|
prosemirror-inputrules "^1.4.0"
|
||||||
|
prosemirror-keymap "^1.2.2"
|
||||||
|
prosemirror-markdown "^1.13.1"
|
||||||
|
prosemirror-menu "^1.2.4"
|
||||||
|
prosemirror-model "^1.24.1"
|
||||||
|
prosemirror-schema-basic "^1.2.3"
|
||||||
|
prosemirror-schema-list "^1.5.0"
|
||||||
|
prosemirror-state "^1.4.3"
|
||||||
|
prosemirror-tables "^1.6.4"
|
||||||
|
prosemirror-trailing-node "^3.0.0"
|
||||||
|
prosemirror-transform "^1.10.2"
|
||||||
|
prosemirror-view "^1.38.1"
|
||||||
|
|
||||||
"@trysound/sax@0.2.0":
|
"@trysound/sax@0.2.0":
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
||||||
@@ -1909,6 +1997,24 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||||
|
|
||||||
|
"@types/linkify-it@^5":
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-5.0.0.tgz#21413001973106cda1c3a9b91eedd4ccd5469d76"
|
||||||
|
integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==
|
||||||
|
|
||||||
|
"@types/markdown-it@^14.0.0":
|
||||||
|
version "14.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-14.1.2.tgz#57f2532a0800067d9b934f3521429a2e8bfb4c61"
|
||||||
|
integrity sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==
|
||||||
|
dependencies:
|
||||||
|
"@types/linkify-it" "^5"
|
||||||
|
"@types/mdurl" "^2"
|
||||||
|
|
||||||
|
"@types/mdurl@^2":
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-2.0.0.tgz#d43878b5b20222682163ae6f897b20447233bdfd"
|
||||||
|
integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==
|
||||||
|
|
||||||
"@types/mime@*":
|
"@types/mime@*":
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
|
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
|
||||||
@@ -2986,7 +3092,7 @@ cosmiconfig@^8.1.3:
|
|||||||
parse-json "^5.0.0"
|
parse-json "^5.0.0"
|
||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
|
|
||||||
crelt@^1.0.5, crelt@^1.0.6:
|
crelt@^1.0.0, crelt@^1.0.5, crelt@^1.0.6:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72"
|
resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72"
|
||||||
integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
|
integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
|
||||||
@@ -4780,6 +4886,18 @@ lines-and-columns@^1.1.6:
|
|||||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||||
|
|
||||||
|
linkify-it@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421"
|
||||||
|
integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==
|
||||||
|
dependencies:
|
||||||
|
uc.micro "^2.0.0"
|
||||||
|
|
||||||
|
linkifyjs@^4.3.2:
|
||||||
|
version "4.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.3.2.tgz#d97eb45419aabf97ceb4b05a7adeb7b8c8ade2b1"
|
||||||
|
integrity sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==
|
||||||
|
|
||||||
loader-runner@^4.3.1:
|
loader-runner@^4.3.1:
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.1.tgz#6c76ed29b0ccce9af379208299f07f876de737e3"
|
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.1.tgz#6c76ed29b0ccce9af379208299f07f876de737e3"
|
||||||
@@ -4867,6 +4985,23 @@ make-dir@^3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
semver "^6.0.0"
|
semver "^6.0.0"
|
||||||
|
|
||||||
|
markdown-it@^14.0.0:
|
||||||
|
version "14.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45"
|
||||||
|
integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==
|
||||||
|
dependencies:
|
||||||
|
argparse "^2.0.1"
|
||||||
|
entities "^4.4.0"
|
||||||
|
linkify-it "^5.0.0"
|
||||||
|
mdurl "^2.0.0"
|
||||||
|
punycode.js "^2.3.1"
|
||||||
|
uc.micro "^2.1.0"
|
||||||
|
|
||||||
|
marked@^17.0.1:
|
||||||
|
version "17.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/marked/-/marked-17.0.1.tgz#9db34197ac145e5929572ee49ef701e37ee9b2e6"
|
||||||
|
integrity sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==
|
||||||
|
|
||||||
math-intrinsics@^1.1.0:
|
math-intrinsics@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
||||||
@@ -4897,6 +5032,11 @@ mdn-data@2.0.30:
|
|||||||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc"
|
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc"
|
||||||
integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==
|
integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==
|
||||||
|
|
||||||
|
mdurl@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0"
|
||||||
|
integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
@@ -5218,6 +5358,11 @@ optionator@^0.9.1:
|
|||||||
type-check "^0.4.0"
|
type-check "^0.4.0"
|
||||||
word-wrap "^1.2.3"
|
word-wrap "^1.2.3"
|
||||||
|
|
||||||
|
orderedmap@^2.0.0:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-2.1.1.tgz#61481269c44031c449915497bf5a4ad273c512d2"
|
||||||
|
integrity sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==
|
||||||
|
|
||||||
p-limit@^2.2.0:
|
p-limit@^2.2.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
|
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
|
||||||
@@ -5739,6 +5884,160 @@ proper-lockfile@^4.1.2:
|
|||||||
retry "^0.12.0"
|
retry "^0.12.0"
|
||||||
signal-exit "^3.0.2"
|
signal-exit "^3.0.2"
|
||||||
|
|
||||||
|
prosemirror-changeset@^2.3.0:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-changeset/-/prosemirror-changeset-2.3.1.tgz#eee3299cfabc7a027694e9abdc4e85505e9dd5e7"
|
||||||
|
integrity sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-transform "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-collab@^1.3.1:
|
||||||
|
version "1.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz#0e8c91e76e009b53457eb3b3051fb68dad029a33"
|
||||||
|
integrity sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-commands@^1.0.0, prosemirror-commands@^1.6.2:
|
||||||
|
version "1.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz#d101fef85618b1be53d5b99ea17bee5600781b38"
|
||||||
|
integrity sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.0.0"
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-transform "^1.10.2"
|
||||||
|
|
||||||
|
prosemirror-dropcursor@^1.8.1:
|
||||||
|
version "1.8.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz#2ed30c4796109ddeb1cf7282372b3850528b7228"
|
||||||
|
integrity sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-transform "^1.1.0"
|
||||||
|
prosemirror-view "^1.1.0"
|
||||||
|
|
||||||
|
prosemirror-gapcursor@^1.3.2:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.0.tgz#e1144a83b79db7ed0ec32cd0e915a0364220af43"
|
||||||
|
integrity sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-keymap "^1.0.0"
|
||||||
|
prosemirror-model "^1.0.0"
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-view "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-history@^1.0.0, prosemirror-history@^1.4.1:
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.5.0.tgz#ee21fc5de85a1473e3e3752015ffd6d649a06859"
|
||||||
|
integrity sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state "^1.2.2"
|
||||||
|
prosemirror-transform "^1.0.0"
|
||||||
|
prosemirror-view "^1.31.0"
|
||||||
|
rope-sequence "^1.3.0"
|
||||||
|
|
||||||
|
prosemirror-inputrules@^1.4.0:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz#d2e935f6086e3801486b09222638f61dae89a570"
|
||||||
|
integrity sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-transform "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.2.2, prosemirror-keymap@^1.2.3:
|
||||||
|
version "1.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz#c0f6ab95f75c0b82c97e44eb6aaf29cbfc150472"
|
||||||
|
integrity sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
w3c-keyname "^2.2.0"
|
||||||
|
|
||||||
|
prosemirror-markdown@^1.13.1:
|
||||||
|
version "1.13.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz#4620e6a0580cd52b5fc8e352c7e04830cd4b3048"
|
||||||
|
integrity sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==
|
||||||
|
dependencies:
|
||||||
|
"@types/markdown-it" "^14.0.0"
|
||||||
|
markdown-it "^14.0.0"
|
||||||
|
prosemirror-model "^1.25.0"
|
||||||
|
|
||||||
|
prosemirror-menu@^1.2.4:
|
||||||
|
version "1.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.5.tgz#dea00e7b623cea89f4d76963bee22d2ac2343250"
|
||||||
|
integrity sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==
|
||||||
|
dependencies:
|
||||||
|
crelt "^1.0.0"
|
||||||
|
prosemirror-commands "^1.0.0"
|
||||||
|
prosemirror-history "^1.0.0"
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-model@^1.0.0, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.24.1, prosemirror-model@^1.25.0, prosemirror-model@^1.25.4:
|
||||||
|
version "1.25.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.25.4.tgz#8ebfbe29ecbee9e5e2e4048c4fe8e363fcd56e7c"
|
||||||
|
integrity sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==
|
||||||
|
dependencies:
|
||||||
|
orderedmap "^2.0.0"
|
||||||
|
|
||||||
|
prosemirror-schema-basic@^1.2.3:
|
||||||
|
version "1.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz#389ce1ec09b8a30ea9bbb92c58569cb690c2d695"
|
||||||
|
integrity sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.25.0"
|
||||||
|
|
||||||
|
prosemirror-schema-list@^1.5.0:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz#5869c8f749e8745c394548bb11820b0feb1e32f5"
|
||||||
|
integrity sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.0.0"
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-transform "^1.7.3"
|
||||||
|
|
||||||
|
prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.4.3, prosemirror-state@^1.4.4:
|
||||||
|
version "1.4.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.4.tgz#72b5e926f9e92dcee12b62a05fcc8a2de3bf5b39"
|
||||||
|
integrity sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.0.0"
|
||||||
|
prosemirror-transform "^1.0.0"
|
||||||
|
prosemirror-view "^1.27.0"
|
||||||
|
|
||||||
|
prosemirror-tables@^1.6.4:
|
||||||
|
version "1.8.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz#104427012e5a5da1d2a38c122efee8d66bdd5104"
|
||||||
|
integrity sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-keymap "^1.2.3"
|
||||||
|
prosemirror-model "^1.25.4"
|
||||||
|
prosemirror-state "^1.4.4"
|
||||||
|
prosemirror-transform "^1.10.5"
|
||||||
|
prosemirror-view "^1.41.4"
|
||||||
|
|
||||||
|
prosemirror-trailing-node@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz#5bc223d4fc1e8d9145e4079ec77a932b54e19e04"
|
||||||
|
integrity sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==
|
||||||
|
dependencies:
|
||||||
|
"@remirror/core-constants" "3.0.0"
|
||||||
|
escape-string-regexp "^4.0.0"
|
||||||
|
|
||||||
|
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.10.2, prosemirror-transform@^1.10.5, prosemirror-transform@^1.7.3:
|
||||||
|
version "1.11.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.11.0.tgz#f5c5050354423dc83c6b083f6f1959ec86a3f9ba"
|
||||||
|
integrity sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.21.0"
|
||||||
|
|
||||||
|
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.38.1, prosemirror-view@^1.41.4:
|
||||||
|
version "1.41.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.41.5.tgz#3e152d14af633f2f5a73aba24e6130c63f643b2b"
|
||||||
|
integrity sha512-UDQbIPnDrjE8tqUBbPmCOZgtd75htE6W3r0JCmY9bL6W1iemDM37MZEKC49d+tdQ0v/CKx4gjxLoLsfkD2NiZA==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.20.0"
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-transform "^1.1.0"
|
||||||
|
|
||||||
proxy-addr@~2.0.7:
|
proxy-addr@~2.0.7:
|
||||||
version "2.0.7"
|
version "2.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
|
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
|
||||||
@@ -5752,6 +6051,11 @@ proxy-from-env@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
|
punycode.js@^2.3.1:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7"
|
||||||
|
integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==
|
||||||
|
|
||||||
punycode@^2.1.0:
|
punycode@^2.1.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
|
||||||
@@ -6010,6 +6314,11 @@ rollbar@^2.26.4:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
decache "^3.0.5"
|
decache "^3.0.5"
|
||||||
|
|
||||||
|
rope-sequence@^1.3.0:
|
||||||
|
version "1.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.4.tgz#df85711aaecd32f1e756f76e43a415171235d425"
|
||||||
|
integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==
|
||||||
|
|
||||||
run-applescript@^7.0.0:
|
run-applescript@^7.0.0:
|
||||||
version "7.1.0"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.1.0.tgz#2e9e54c4664ec3106c5b5630e249d3d6595c4911"
|
resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.1.0.tgz#2e9e54c4664ec3106c5b5630e249d3d6595c4911"
|
||||||
@@ -6792,6 +7101,11 @@ typed-function@^4.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-4.1.1.tgz#38ce3cae31f4f513bcb263563fdad27b2afa73e8"
|
resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-4.1.1.tgz#38ce3cae31f4f513bcb263563fdad27b2afa73e8"
|
||||||
integrity sha512-Pq1DVubcvibmm8bYcMowjVnnMwPVMeh0DIdA8ad8NZY2sJgapANJmiigSUwlt+EgXxpfIv8MWrQXTIzkfYZLYQ==
|
integrity sha512-Pq1DVubcvibmm8bYcMowjVnnMwPVMeh0DIdA8ad8NZY2sJgapANJmiigSUwlt+EgXxpfIv8MWrQXTIzkfYZLYQ==
|
||||||
|
|
||||||
|
uc.micro@^2.0.0, uc.micro@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee"
|
||||||
|
integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==
|
||||||
|
|
||||||
unbox-primitive@^1.0.2:
|
unbox-primitive@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
|
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
|
||||||
@@ -6934,7 +7248,7 @@ vue@^3.3.2:
|
|||||||
"@vue/server-renderer" "3.3.4"
|
"@vue/server-renderer" "3.3.4"
|
||||||
"@vue/shared" "3.3.4"
|
"@vue/shared" "3.3.4"
|
||||||
|
|
||||||
w3c-keyname@^2.2.4:
|
w3c-keyname@^2.2.0, w3c-keyname@^2.2.4:
|
||||||
version "2.2.8"
|
version "2.2.8"
|
||||||
resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5"
|
resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5"
|
||||||
integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==
|
integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==
|
||||||
|
|||||||
Reference in New Issue
Block a user