mirror of
https://github.com/docusealco/docuseal
synced 2026-11-04 06:42:32 -05:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c65b0e4ba | ||
|
|
ced5ab67ab | ||
|
|
28c4177128 | ||
|
|
5d86a08b5f | ||
|
|
a69fb81429 | ||
|
|
e6ac3380d4 | ||
|
|
3a535e7112 | ||
|
|
7464f9cfad | ||
|
|
58e24ef758 | ||
|
|
c1d809f989 | ||
|
|
80b24f0e2a | ||
|
|
2e253904a3 | ||
|
|
a7f381caf0 |
No files matched your search
+5
-5
@@ -524,11 +524,11 @@ GEM
|
||||
simplecov-html (0.13.2)
|
||||
simplecov_json_formatter (0.1.4)
|
||||
smart_properties (1.17.0)
|
||||
sqlite3 (2.9.5-aarch64-linux-gnu)
|
||||
sqlite3 (2.9.5-aarch64-linux-musl)
|
||||
sqlite3 (2.9.5-arm64-darwin)
|
||||
sqlite3 (2.9.5-x86_64-linux-gnu)
|
||||
sqlite3 (2.9.5-x86_64-linux-musl)
|
||||
sqlite3 (2.9.6-aarch64-linux-gnu)
|
||||
sqlite3 (2.9.6-aarch64-linux-musl)
|
||||
sqlite3 (2.9.6-arm64-darwin)
|
||||
sqlite3 (2.9.6-x86_64-linux-gnu)
|
||||
sqlite3 (2.9.6-x86_64-linux-musl)
|
||||
strip_attributes (2.0.1)
|
||||
activemodel (>= 3.0, < 9.0)
|
||||
strscan (3.1.8)
|
||||
|
||||
@@ -118,7 +118,12 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def sign_in_for_demo
|
||||
sign_in(User.active.order('random()').take) unless signed_in?
|
||||
return if signed_in?
|
||||
|
||||
account = Account.create!(name: "Demo #{SecureRandom.hex(3)}")
|
||||
|
||||
sign_in(account.users.create!(first_name: 'Demo', last_name: 'User',
|
||||
email: "#{SecureRandom.hex}@docuseal.com", password: SecureRandom.hex))
|
||||
end
|
||||
|
||||
def current_account
|
||||
|
||||
@@ -66,6 +66,8 @@ class SubmissionsController < ApplicationController
|
||||
create_submissions(@template, submissions_params, params)
|
||||
end
|
||||
|
||||
raise Submissions::CreateFromSubmitters::BaseError, 'Invalid email address' if submissions.blank?
|
||||
|
||||
WebhookUrls.enqueue_events(submissions, 'submission.created')
|
||||
|
||||
Submissions.send_signature_requests(submissions)
|
||||
|
||||
@@ -81,9 +81,26 @@ class SubmittersController < ApplicationController
|
||||
|
||||
submitter.name = attrs[:name] if attrs.key?(:name)
|
||||
|
||||
if submitter_changed?(submitter)
|
||||
submitter.submitter_versions.new(slug: submitter.slug, email: submitter.email_was,
|
||||
name: submitter.name_was, phone: submitter.phone_was)
|
||||
|
||||
submitter.slug = SecureRandom.base58(14)
|
||||
submitter.values = Submitters.fetch_values_for_delegate(submitter)
|
||||
end
|
||||
|
||||
submitter
|
||||
end
|
||||
|
||||
def submitter_changed?(submitter)
|
||||
if submitter.email_was.blank? && submitter.phone_was.blank?
|
||||
submitter.name_was.present? && submitter.name_changed?
|
||||
else
|
||||
(submitter.email_was.present? && submitter.email_changed?) ||
|
||||
(submitter.phone_was.present? && submitter.phone_changed?)
|
||||
end
|
||||
end
|
||||
|
||||
def submitter_params
|
||||
params.require(:submitter).permit(:email, :name, :phone).transform_values(&:strip)
|
||||
end
|
||||
|
||||
@@ -35,6 +35,9 @@ import PromptPassword from './elements/prompt_password'
|
||||
import EmailsTextarea from './elements/emails_textarea'
|
||||
import ToggleSubmit from './elements/toggle_submit'
|
||||
import ToggleOnSubmit from './elements/toggle_on_submit'
|
||||
import ToggleOnChecked from './elements/toggle_on_checked'
|
||||
import ToggleSendTitle from './elements/toggle_send_title'
|
||||
import AppendTemplate from './elements/append_template'
|
||||
import CheckOnClick from './elements/check_on_click'
|
||||
import PasswordInput from './elements/password_input'
|
||||
import SearchInput from './elements/search_input'
|
||||
@@ -159,6 +162,9 @@ safeRegisterElement('emails-textarea', EmailsTextarea)
|
||||
safeRegisterElement('toggle-cookies', ToggleCookies)
|
||||
safeRegisterElement('toggle-submit', ToggleSubmit)
|
||||
safeRegisterElement('toggle-on-submit', ToggleOnSubmit)
|
||||
safeRegisterElement('toggle-on-checked', ToggleOnChecked)
|
||||
safeRegisterElement('toggle-send-title', ToggleSendTitle)
|
||||
safeRegisterElement('append-template', AppendTemplate)
|
||||
safeRegisterElement('password-input', PasswordInput)
|
||||
safeRegisterElement('search-input', SearchInput)
|
||||
safeRegisterElement('toggle-attribute', ToggleAttribute)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
export default class extends HTMLElement {
|
||||
connectedCallback () {
|
||||
this.addEventListener('click', this.onClick)
|
||||
}
|
||||
|
||||
disconnectedCallback () {
|
||||
this.removeEventListener('click', this.onClick)
|
||||
}
|
||||
|
||||
onClick = (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
const target = document.getElementById(this.dataset.targetId)
|
||||
const item = this.querySelector('template').content.firstElementChild.cloneNode(true)
|
||||
|
||||
item.querySelector('a').addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
item.remove()
|
||||
|
||||
target.classList.toggle('hidden', !target.childElementCount)
|
||||
})
|
||||
|
||||
target.append(item)
|
||||
target.classList.remove('hidden')
|
||||
|
||||
item.querySelector('input').focus()
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { actionable } from '@github/catalyst/lib/actionable'
|
||||
import { targets, targetable } from '@github/catalyst/lib/targetable'
|
||||
|
||||
export default actionable(targetable(class extends HTMLElement {
|
||||
static [targets.static] = ['items']
|
||||
static [targets.static] = ['items', 'groups']
|
||||
|
||||
addItem (e) {
|
||||
e.preventDefault()
|
||||
@@ -24,11 +24,28 @@ export default actionable(targetable(class extends HTMLElement {
|
||||
duplicateItem.querySelectorAll('a.hidden').forEach((button) => button.classList.toggle('hidden'))
|
||||
|
||||
originalItem.parentNode.append(duplicateItem)
|
||||
|
||||
this.toggleMultipleClasses()
|
||||
|
||||
duplicateItem.querySelector("input:not([type='hidden'])")?.focus()
|
||||
}
|
||||
|
||||
removeItem (e) {
|
||||
e.preventDefault()
|
||||
|
||||
this.items.find((item) => item.contains(e.target))?.remove()
|
||||
|
||||
this.toggleMultipleClasses()
|
||||
}
|
||||
|
||||
toggleMultipleClasses () {
|
||||
const isMultiple = this.items.length > 1
|
||||
const elements = [...this.items, ...this.groups]
|
||||
|
||||
elements.forEach((element) => {
|
||||
const classes = element.dataset.multipleClasses || this.dataset.multipleClasses
|
||||
|
||||
classes?.split(' ').forEach((cls) => element.classList.toggle(cls, isMultiple))
|
||||
})
|
||||
}
|
||||
}))
|
||||
@@ -0,0 +1,23 @@
|
||||
export default class extends HTMLElement {
|
||||
connectedCallback () {
|
||||
this.form.addEventListener('change', this.toggle)
|
||||
|
||||
this.toggle()
|
||||
}
|
||||
|
||||
disconnectedCallback () {
|
||||
this.form.removeEventListener('change', this.toggle)
|
||||
}
|
||||
|
||||
toggle = () => {
|
||||
const selector = this.dataset.names.split(' ').map((name) => `[name="${name}"]:checked:enabled`).join(', ')
|
||||
const isChecked = !!this.form.querySelector(selector)
|
||||
|
||||
this.firstElementChild.classList.toggle('hidden', !isChecked)
|
||||
this.lastElementChild.classList.toggle('hidden', isChecked)
|
||||
}
|
||||
|
||||
get form () {
|
||||
return this.closest('form')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
export default class extends HTMLElement {
|
||||
connectedCallback () {
|
||||
this.events.forEach((event) => this.form.addEventListener(event, this.toggle))
|
||||
|
||||
this.toggle()
|
||||
}
|
||||
|
||||
disconnectedCallback () {
|
||||
this.events.forEach((event) => this.form.removeEventListener(event, this.toggle))
|
||||
}
|
||||
|
||||
toggle = (event) => {
|
||||
if (event?.type === 'input' && event.target.matches(this.fieldSelector('name'))) return
|
||||
|
||||
const isNameOnly = (field) => this.isFilled('name') && !this.isFilled(field)
|
||||
|
||||
const isSend = (this.isChecked('send_email') && !isNameOnly('email')) ||
|
||||
(this.isChecked('send_sms') && !isNameOnly('phone'))
|
||||
|
||||
this.firstElementChild.classList.toggle('hidden', !isSend)
|
||||
this.lastElementChild.classList.toggle('hidden', isSend)
|
||||
}
|
||||
|
||||
isChecked (name) {
|
||||
return !!this.form.querySelector(`[name="${name}"]:checked:enabled`)
|
||||
}
|
||||
|
||||
isFilled (field) {
|
||||
return [...this.form.querySelectorAll(this.fieldSelector(field))].some((input) => input.value.trim())
|
||||
}
|
||||
|
||||
fieldSelector (field) {
|
||||
return `[name$="[][${field}]"]`
|
||||
}
|
||||
|
||||
get events () {
|
||||
return ['change', 'input', 'linked-input.update']
|
||||
}
|
||||
|
||||
get form () {
|
||||
return this.closest('form')
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,9 @@ const ICONS = {
|
||||
user: 'person',
|
||||
users: 'person.2',
|
||||
users_plus: 'person.badge.plus',
|
||||
user_plus: 'person.badge.plus',
|
||||
eye_plus: 'eye',
|
||||
mail_plus: 'envelope',
|
||||
photo: 'photo',
|
||||
settings: 'gearshape',
|
||||
logout: 'rectangle.portrait.and.arrow.right',
|
||||
|
||||
@@ -319,7 +319,7 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['start-resize', 'stop-resize', 'start-drag', 'stop-drag', 'remove', 'scroll-to', 'add-custom-field', 'click-title', 'multi-select'],
|
||||
emits: ['start-resize', 'stop-resize', 'start-drag', 'stop-drag', 'remove', 'scroll-to', 'add-custom-field', 'click-title'],
|
||||
data () {
|
||||
return {
|
||||
isContenteditable: false,
|
||||
@@ -798,8 +798,6 @@ export default {
|
||||
this.selectedAreasRef.value.splice(this.selectedAreasRef.value.indexOf(this.area), 1)
|
||||
}
|
||||
|
||||
this.$emit('multi-select', e)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
ref="dragContainer"
|
||||
style="max-width: 1600px"
|
||||
:class="nativeView ? (isSheetView ? 'bg-base-100' : 'px-4') : 'mx-auto pl-3 md:pl-4 h-full'"
|
||||
@dragstart="isInternalDrag = true"
|
||||
@dragend="isInternalDrag = false"
|
||||
@dragover="onDragover"
|
||||
@drop="isDragFile = false"
|
||||
@drop="[isDragFile = false, isInternalDrag = false]"
|
||||
>
|
||||
<HoverDropzone
|
||||
v-if="sortedDocuments.length && withUploadButton && editable && !isSheetView"
|
||||
@@ -1390,6 +1392,7 @@ export default {
|
||||
drawOption: null,
|
||||
dragField: null,
|
||||
isDragFile: false,
|
||||
isInternalDrag: false,
|
||||
isMathLoaded: false,
|
||||
isRevisionsModalOpen: false,
|
||||
isDocumentsDrawerOpen: false,
|
||||
@@ -2039,8 +2042,18 @@ export default {
|
||||
|
||||
ref.x = e.clientX - ref.offsetX
|
||||
ref.y = e.clientY - ref.offsetY
|
||||
} else if (e.dataTransfer?.types?.includes('Files') && !this.editModalDocumentUuid) {
|
||||
this.isDragFile = true
|
||||
} else if (e.dataTransfer?.types?.includes('Files') && !this.editModalDocumentUuid && !this.isInternalDrag) {
|
||||
const items = Array.from(e.dataTransfer.items)
|
||||
|
||||
if (this.dynamicDocuments.length && items.length && items.every((item) => item.type.startsWith('image/'))) {
|
||||
if (!e.defaultPrevented) {
|
||||
e.preventDefault()
|
||||
|
||||
e.dataTransfer.dropEffect = 'none'
|
||||
}
|
||||
} else {
|
||||
this.isDragFile = true
|
||||
}
|
||||
}
|
||||
},
|
||||
onWindowDragLeave (event) {
|
||||
|
||||
@@ -639,6 +639,20 @@ export default {
|
||||
|
||||
if (!file) return
|
||||
|
||||
const image = await this.uploadImage(file)
|
||||
|
||||
if (image) {
|
||||
this.editor.chain().focus().insertContent(image).run()
|
||||
}
|
||||
},
|
||||
async insertImageFiles (files, pos) {
|
||||
const images = (await Promise.all(files.map(this.uploadImage))).filter(Boolean)
|
||||
|
||||
if (images.length) {
|
||||
this.editor.chain().focus().insertContentAt(pos, images).run()
|
||||
}
|
||||
},
|
||||
async uploadImage (file) {
|
||||
const formData = new FormData()
|
||||
|
||||
formData.append('file', file)
|
||||
@@ -656,9 +670,7 @@ export default {
|
||||
|
||||
await this.$nextTick()
|
||||
|
||||
this.editor.chain().focus()
|
||||
.insertContent({ type: 'image', attrs: { htmlAttrs: { src: `blob:${data.uuid}`, style: 'max-width: 100%' } } })
|
||||
.run()
|
||||
return { type: 'image', attrs: { htmlAttrs: { src: `blob:${data.uuid}`, style: 'max-width: 100%' } } }
|
||||
},
|
||||
setDynamicMenuCoords (editor) {
|
||||
const { from, to } = editor.state.selection
|
||||
@@ -975,7 +987,7 @@ export default {
|
||||
onSelectedAreaChange () {
|
||||
this.save()
|
||||
},
|
||||
onFieldDrop (view, event, _slice, moved) {
|
||||
onFieldDrop (view, event, slice, moved) {
|
||||
this.isAreaDrag = false
|
||||
|
||||
if (moved) {
|
||||
@@ -983,8 +995,9 @@ export default {
|
||||
}
|
||||
|
||||
const draggedField = this.fieldsDragFieldRef?.value || this.customDragFieldRef?.value || this.dragField
|
||||
const imageFiles = slice.size ? [] : Array.from(event.dataTransfer.files).filter((file) => file.type.startsWith('image/'))
|
||||
|
||||
if (!draggedField) return false
|
||||
if (!draggedField && !imageFiles.length) return false
|
||||
|
||||
event.preventDefault()
|
||||
|
||||
@@ -992,14 +1005,18 @@ export default {
|
||||
|
||||
if (!pos) return false
|
||||
|
||||
this.insertFieldAtRange({
|
||||
sourceField: draggedField,
|
||||
existingField: this.fieldsDragFieldRef?.value,
|
||||
from: pos.pos
|
||||
})
|
||||
if (draggedField) {
|
||||
this.insertFieldAtRange({
|
||||
sourceField: draggedField,
|
||||
existingField: this.fieldsDragFieldRef?.value,
|
||||
from: pos.pos
|
||||
})
|
||||
|
||||
this.fieldsDragFieldRef.value = null
|
||||
this.customDragFieldRef.value = null
|
||||
this.fieldsDragFieldRef.value = null
|
||||
this.customDragFieldRef.value = null
|
||||
} else {
|
||||
this.insertImageFiles(imageFiles, pos.pos)
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
@scroll-to="$emit('scroll-to', $event)"
|
||||
@add-custom-field="$emit('add-custom-field', $event)"
|
||||
@contextmenu="openAreaContextMenu($event, item.area, item.field)"
|
||||
@multi-select="openMultiSelectContextMenu"
|
||||
@click-title="closeContextMenu"
|
||||
/>
|
||||
<FieldArea
|
||||
@@ -450,13 +449,6 @@ export default {
|
||||
areas: this.selectedAreasRef.value
|
||||
}
|
||||
},
|
||||
openMultiSelectContextMenu (event) {
|
||||
if (this.selectedAreasRef.value.length >= 2) {
|
||||
this.openSelectionContextMenu(event)
|
||||
} else {
|
||||
this.closeContextMenu()
|
||||
}
|
||||
},
|
||||
handleSelectionCopy () {
|
||||
this.$emit('copy-selected-areas')
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::DOWNLOAD_LINKS_EXPIRE_KEY) %>
|
||||
<% if can?(:manage, account_config) %>
|
||||
<% if !Docuseal.demo? && can?(:manage, account_config) %>
|
||||
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
||||
<%= f.hidden_field :key %>
|
||||
<div class="flex items-center justify-between gap-4 py-2.5">
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M12 18c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6" />
|
||||
<path d="M16 19h6" />
|
||||
<path d="M19 16v6" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 460 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 19h-7a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v5.5" />
|
||||
<path d="M16 19h6" />
|
||||
<path d="M19 16v6" />
|
||||
<path d="M3 7l9 6l9 -6" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 441 B |
@@ -1,8 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" />
|
||||
<path d="M3 21v-2a4 4 0 0 1 4 -4h4c.96 0 1.84 .338 2.53 .901" />
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
|
||||
<path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" />
|
||||
<path d="M16 19h6" />
|
||||
<path d="M19 16v6" />
|
||||
<path d="M6 21v-2a4 4 0 0 1 4 -4h4" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 421 B |
@@ -3,7 +3,7 @@
|
||||
<div class="w-full text-center">
|
||||
<span class="font-bold"><%= t('demo_environment') %></span>
|
||||
<br>
|
||||
<%= t('create_a_new_template_document_form_or_submit_the_existing_one_html', new_template_link: new_template_path, start_form_link: start_form_url(slug: ::Template.first&.slug)) %> 😊
|
||||
<%= t('create_a_new_template_document_form_html', new_template_link: new_template_path) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -12,7 +12,7 @@
|
||||
<div>
|
||||
<p dir="auto" class="text-lg font-bold mb-1"><%= @submitter.submission.template&.name %></p>
|
||||
<p dir="auto" class="text-sm">
|
||||
<%= t(@submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(@submitter.completed_at.to_date, format: :long)) %>
|
||||
<%= t(@submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(@submitter.completed_at.in_time_zone(@submitter.account.timezone).to_date, format: :long)) %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<% fields_id = "add_new_fields_#{SecureRandom.hex(3)}" %>
|
||||
<div id="<%= fields_id %>" class="space-y-3 mt-4 hidden" data-targets="dynamic-list.groups" data-multiple-classes="px-3 pt-3 pb-4 rounded-xl border border-dashed border-base-300"></div>
|
||||
<native-menu class="<%= turbo_native_app? ? 'block' : 'dropdown block max-sm:hidden' %> mt-4 -mb-2">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm normal-case font-normal w-full flex items-center justify-center border-dashed border-base-300 hover:border-base-content/20 !bg-transparent">
|
||||
<%= svg_icon('users_plus', class: 'w-4 h-4 stroke-2') %>
|
||||
<span><%= t('add_new') %></span>
|
||||
</label>
|
||||
<ul tabindex="0" class="<%= turbo_native_app? ? 'hidden' : 'z-10 dropdown-content p-2 mt-1 shadow menu bg-base-100 rounded-box' %>" style="left: 50%; --tw-translate-x: -50%">
|
||||
<li>
|
||||
<native-menu-action data-icon="user_plus" data-label="<%= t('recipients') %>" class="grid-cols-1 p-0">
|
||||
<a href="#" class="flex items-center gap-2 px-4 py-2" data-action="click:dynamic-list#addItem">
|
||||
<%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
|
||||
<span class="whitespace-nowrap"><%= t('recipients') %></span>
|
||||
</a>
|
||||
</native-menu-action>
|
||||
</li>
|
||||
<append-template class="contents" data-target-id="<%= fields_id %>">
|
||||
<li>
|
||||
<native-menu-action data-icon="eye_plus" data-label="<%= t('cc_view_only') %>" class="grid-cols-1 p-0">
|
||||
<a href="#" class="flex items-center gap-2 px-4 py-2">
|
||||
<%= svg_icon('eye_plus', class: 'w-4 h-4 stroke-2') %>
|
||||
<span class="whitespace-nowrap"><%= t('cc_view_only') %></span>
|
||||
</a>
|
||||
</native-menu-action>
|
||||
</li>
|
||||
<template>
|
||||
<submitter-item class="form-control">
|
||||
<label class="label pt-0 pb-1">
|
||||
<span class="label-text"><%= t('cc_view_only') %></span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<submitters-autocomplete data-field="email">
|
||||
<input type="email" name="cc_recipients[]" autocomplete="off" class="base-input !h-10 w-full pr-10" placeholder="<%= t('email') %>">
|
||||
</submitters-autocomplete>
|
||||
<a href="#" class="absolute right-2 top-2 block w-6 h-6 text-neutral-700 p-1 hover:text-base-content">
|
||||
<%= svg_icon('trash', class: 'w-4 h-4') %>
|
||||
</a>
|
||||
</div>
|
||||
</submitter-item>
|
||||
</template>
|
||||
</append-template>
|
||||
<append-template class="contents" data-target-id="<%= fields_id %>">
|
||||
<li>
|
||||
<native-menu-action data-icon="mail_plus" data-label="<%= t('bcc_completed') %>" class="grid-cols-1 p-0">
|
||||
<a href="#" class="flex items-center gap-2 px-4 py-2">
|
||||
<%= svg_icon('mail_plus', class: 'w-4 h-4 stroke-2') %>
|
||||
<span class="whitespace-nowrap"><%= t('bcc_completed') %></span>
|
||||
</a>
|
||||
</native-menu-action>
|
||||
</li>
|
||||
<template>
|
||||
<div class="form-control">
|
||||
<label class="label pt-0 pb-1">
|
||||
<span class="label-text"><%= t('bcc_completed') %></span>
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input type="email" name="bcc_completed[]" autocomplete="off" class="base-input !h-10 w-full pr-10" placeholder="<%= t('email') %>">
|
||||
<a href="#" class="absolute right-2 top-2 block w-6 h-6 text-neutral-700 p-1 hover:text-base-content">
|
||||
<%= svg_icon('trash', class: 'w-4 h-4') %>
|
||||
</a>
|
||||
</div>
|
||||
<% default_bcc_completed = template.preferences['bcc_completed'].presence || current_account.account_configs.find_by(key: AccountConfig::BCC_EMAILS)&.value %>
|
||||
<% if default_bcc_completed.present? %>
|
||||
<input type="hidden" name="bcc_completed[]" value="<%= default_bcc_completed %>">
|
||||
<% end %>
|
||||
</div>
|
||||
</template>
|
||||
</append-template>
|
||||
</ul>
|
||||
</native-menu>
|
||||
@@ -1,12 +1,12 @@
|
||||
<% 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: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
||||
<% 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="block" data-multiple-classes="px-3 <%= submitters.size > 1 ? 'pt-3 pb-4' : 'py-4' %> rounded-xl border border-dashed border-base-300">
|
||||
<div class="space-y-4">
|
||||
<div class="relative <%= 'p-4 rounded-xl bg-base-300/40 max-sm:p-0 max-sm:bg-transparent' unless local_assigns[:variables_form] %>" data-targets="dynamic-list.items">
|
||||
<div class="relative" data-targets="dynamic-list.items">
|
||||
<div>
|
||||
<div class="absolute right-4 top-5">
|
||||
<a href="#" data-action="click:dynamic-list#removeItem" class="<%= submitters.size == 1 ? 'right-2 top-1' : '-top-3' %> relative block w-6 h-6 rounded-lg text-neutral-700 text-center bg-base-300 p-1 hidden hover:bg-neutral hover:text-white">
|
||||
<div class="absolute top-5" style="right: 12px">
|
||||
<a href="#" data-action="click:dynamic-list#removeItem" class="<%= submitters.size == 1 ? 'right-2 top-1' : '-top-3' %> relative block w-6 h-6 text-neutral-700 p-1 hidden hover:text-base-content">
|
||||
<%= svg_icon('trash', class: 'w-4 h-4') %>
|
||||
</a>
|
||||
</div>
|
||||
@@ -86,14 +86,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<% if params[:selfsign].blank? && local_assigns[:prefillable_fields].blank? && local_assigns[:recipient_form_fields].blank? && local_assigns[:variables_form].blank? %>
|
||||
<a href="#" class="btn btn-primary btn-sm w-full flex items-center justify-center max-sm:hidden" data-action="click:dynamic-list#addItem">
|
||||
<%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
|
||||
<span><%= t('add_new') %></span>
|
||||
</a>
|
||||
<%= render 'add_new', template: %>
|
||||
<% end %>
|
||||
</dynamic-list>
|
||||
<%= local_assigns[:variables_form] %>
|
||||
<div>
|
||||
<div class="mt-4">
|
||||
<%= render('submitters_order', f:, template:) if can_send_emails %>
|
||||
<%= render 'send_email', f:, template:, can_send_emails:, viewer_submitter_uuids: local_assigns[:viewer_submitter_uuids] %>
|
||||
<% if has_phone_field %>
|
||||
@@ -101,7 +98,12 @@
|
||||
<% end %>
|
||||
<%= render 'extra_fields', f: %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= f.button button_title(title: t('add_recipients')), class: 'base-button' %>
|
||||
<div class="form-control mt-4">
|
||||
<%= f.button class: 'base-button' do %>
|
||||
<toggle-send-title>
|
||||
<span><%= button_title(title: t('send'), disabled_with: t('sending')) %></span>
|
||||
<span class="hidden"><%= button_title(title: t('add_recipients')) %></span>
|
||||
</toggle-send-title>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -1,4 +1,4 @@
|
||||
<%= 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: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
||||
<% 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 && local_assigns[:variables_form] %>
|
||||
<% item = submitters.first %>
|
||||
@@ -26,18 +26,18 @@
|
||||
<emails-textarea data-bulk-enabled="<%= Docuseal.demo? || !Docuseal.multitenant? || can?(:manage, :bulk_send) %>" data-limit="<%= Docuseal.multitenant? ? (can?(:manage, :bulk_send) ? 40 : 1) : nil %>">
|
||||
<submitters-autocomplete data-field="email" class="block relative">
|
||||
<autoresize-textarea>
|
||||
<%= f.text_area :emails, required: true, class: 'base-textarea w-full !text-lg', placeholder: "#{t('type_emails_here')}...", rows: 2 %>
|
||||
<%= f.text_area :emails, required: true, class: 'base-textarea block w-full !text-lg', placeholder: "#{t('type_emails_here')}...", rows: 2 %>
|
||||
</autoresize-textarea>
|
||||
</submitters-autocomplete>
|
||||
</emails-textarea>
|
||||
</submitter-item>
|
||||
<% else %>
|
||||
<dynamic-list class="space-y-4">
|
||||
<dynamic-list class="block" data-multiple-classes="px-3 pt-3 pb-4 rounded-xl border border-dashed border-base-300">
|
||||
<div class="space-y-4">
|
||||
<div class="relative <%= 'p-4 rounded-xl bg-base-300/40 max-sm:p-0 max-sm:bg-transparent' unless local_assigns[:variables_form] %>" data-targets="dynamic-list.items">
|
||||
<div class="relative" data-targets="dynamic-list.items">
|
||||
<div>
|
||||
<div class="absolute right-4 top-5">
|
||||
<a href="#" data-action="click:dynamic-list#removeItem" class="-top-3 relative block w-6 h-6 rounded-lg text-neutral-700 text-center bg-base-300 p-1 hidden hover:bg-neutral hover:text-white">
|
||||
<div class="absolute top-5" style="right: 12px">
|
||||
<a href="#" data-action="click:dynamic-list#removeItem" class="-top-3 relative block w-6 h-6 text-neutral-700 p-1 hidden hover:text-base-content">
|
||||
<%= svg_icon('trash', class: 'w-4 h-4') %>
|
||||
</a>
|
||||
</div>
|
||||
@@ -60,22 +60,24 @@
|
||||
</div>
|
||||
</div>
|
||||
<% if params[:selfsign].blank? && local_assigns[:variables_form].blank? %>
|
||||
<a href="#" class="btn btn-primary btn-sm w-full flex items-center justify-center max-sm:hidden" data-action="click:dynamic-list#addItem">
|
||||
<%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
|
||||
<span><%= t('add_new') %></span>
|
||||
</a>
|
||||
<%= render 'add_new', template: %>
|
||||
<% end %>
|
||||
</dynamic-list>
|
||||
<% end %>
|
||||
<%= local_assigns[:variables_form] %>
|
||||
<div>
|
||||
<div class="mt-4">
|
||||
<%= render('submitters_order', f:, template:) if can_send_emails %>
|
||||
<%= render 'send_email', f:, template:, can_send_emails:, viewer_submitter_uuids: local_assigns[:viewer_submitter_uuids] %>
|
||||
<%= render 'extra_fields', f: %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div class="form-control mt-4">
|
||||
<%= content_for(:submit_button) || capture do %>
|
||||
<%= f.button button_title(title: t('add_recipients')), class: 'base-button' %>
|
||||
<%= f.button class: 'base-button' do %>
|
||||
<toggle-on-checked data-names="send_email send_sms">
|
||||
<span><%= button_title(title: t('send'), disabled_with: t('sending')) %></span>
|
||||
<span class="hidden"><%= button_title(title: t('add_recipients')) %></span>
|
||||
</toggle-on-checked>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -1,11 +1,11 @@
|
||||
<%= 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: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
||||
<% 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="block" data-multiple-classes="px-3 <%= submitters.size > 1 ? 'pt-3 pb-4' : 'py-4' %> rounded-xl border border-dashed border-base-300">
|
||||
<div class="space-y-4">
|
||||
<div class="relative <%= 'p-4 rounded-xl bg-base-300/40 max-sm:p-0 max-sm:bg-transparent' unless local_assigns[:variables_form] %>" data-targets="dynamic-list.items">
|
||||
<div class="relative" data-targets="dynamic-list.items">
|
||||
<div>
|
||||
<div class="absolute right-4 top-5">
|
||||
<a href="#" data-action="click:dynamic-list#removeItem" class="<%= submitters.size == 1 ? 'right-2 top-1' : '-top-3' %> relative block w-6 h-6 rounded-lg text-neutral-700 text-center bg-base-300 p-1 hidden hover:bg-neutral hover:text-white">
|
||||
<div class="absolute top-5" style="right: 12px">
|
||||
<a href="#" data-action="click:dynamic-list#removeItem" class="<%= submitters.size == 1 ? 'right-2 top-1' : '-top-3' %> relative block w-6 h-6 text-neutral-700 p-1 hidden hover:text-base-content">
|
||||
<%= svg_icon('trash', class: 'w-4 h-4') %>
|
||||
</a>
|
||||
</div>
|
||||
@@ -48,19 +48,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<% if params[:selfsign].blank? && local_assigns[:variables_form].blank? %>
|
||||
<a href="#" class="btn btn-primary btn-sm w-full flex items-center justify-center max-sm:hidden" data-action="click:dynamic-list#addItem">
|
||||
<%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
|
||||
<span><%= t('add_new') %></span>
|
||||
</a>
|
||||
<%= render 'add_new', template: %>
|
||||
<% end %>
|
||||
</dynamic-list>
|
||||
<%= local_assigns[:variables_form] %>
|
||||
<div>
|
||||
<div class="mt-4">
|
||||
<%= render 'submitters_order', f:, template: %>
|
||||
<%= render 'send_sms', f:, checked: true %>
|
||||
<%= render 'extra_phone_fields', f: %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= f.button button_title(title: t('add_recipients')), class: 'base-button' %>
|
||||
<div class="form-control mt-4">
|
||||
<%= f.button class: 'base-button' do %>
|
||||
<toggle-on-checked data-names="send_email send_sms">
|
||||
<span><%= button_title(title: t('send'), disabled_with: t('sending')) %></span>
|
||||
<span class="hidden"><%= button_title(title: t('add_recipients')) %></span>
|
||||
</toggle-on-checked>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -14,7 +14,7 @@
|
||||
<toggle-visible data-element-ids="<%= [message_field_id].to_json %>" class="flex">
|
||||
<label>
|
||||
<%= f.check_box :is_custom_message, checked: false, class: 'hidden peer', data: { action: 'change:toggle-visible#trigger', type: 'checkbox' } %>
|
||||
<span class="link peer-checked:hidden"><%= t('edit_message') %></span>
|
||||
<span class="link link-hover peer-checked:hidden"><%= t('edit_message') %></span>
|
||||
</label>
|
||||
</toggle-visible>
|
||||
<% end %>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<% unless turbo_native_ios? %>
|
||||
<div class="form-control">
|
||||
<%= render 'sms_settings/placeholder' %>
|
||||
</div>
|
||||
<toggle-on-checked data-names="is_custom_message" class="block">
|
||||
<div class="form-control">
|
||||
<%= render 'sms_settings/placeholder' %>
|
||||
</div>
|
||||
</toggle-on-checked>
|
||||
<% end %>
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</toggle-visible>
|
||||
<% end %>
|
||||
<div class="px-5 mb-5 mt-4">
|
||||
<div class="px-5 mb-5 mt-5">
|
||||
<% unless only_detailed %>
|
||||
<div id="email" class="<%= 'hidden' if default_tab != 'email' %>">
|
||||
<%= render 'email_form', template: @template, variables_form:, can_send_emails:, viewer_submitter_uuids: %>
|
||||
|
||||
@@ -54,7 +54,8 @@
|
||||
<% if @submission.submitters.to_a.any?(&:completed_at?) %>
|
||||
<% show_combined_download = @submission.completed_at? && !is_combined_enabled %>
|
||||
<% show_unarchive = signed_in? && can?(:destroy, @submission) && @submission.archived_at? && @submission.completed_at? %>
|
||||
<% show_download_dropdown = show_combined_download || show_unarchive %>
|
||||
<% show_event_log_download = signed_in? && can?(:manage, :event_log_download) && can?(:read, @submission) %>
|
||||
<% show_download_dropdown = show_combined_download || show_event_log_download || show_unarchive %>
|
||||
<% if @submission.completed_at? || !is_combined_enabled %>
|
||||
<div class="join relative">
|
||||
<native-action data-label="<%= t('download') %>" data-icon="download">
|
||||
@@ -95,6 +96,9 @@
|
||||
</li>
|
||||
</native-action>
|
||||
<% end %>
|
||||
<% if show_event_log_download %>
|
||||
<%= render 'submissions/download_event_log' %>
|
||||
<% end %>
|
||||
<% if show_unarchive %>
|
||||
<native-action data-label="<%= t('unarchive') %>" data-icon="rotate" data-section="archive">
|
||||
<li>
|
||||
@@ -163,6 +167,7 @@
|
||||
<% value = values[field['uuid']].presence || (field['default_value'] != '{{date}}' && field['readonly'] == true && field['conditions'].blank? && field['default_value'].present? ? Submitters::SubmitValues.template_default_value_for_submitter(field['default_value'], @submission.submitters.find { |e| e.uuid == field['submitter_uuid'] }, with_time: false) : nil) %>
|
||||
<% value ||= field['default_value'] if field['type'] == 'heading' %>
|
||||
<% submitter = submitters_index[field['submitter_uuid']] %>
|
||||
<% value = nil if field['type'] == 'signature' && submitter && !submitter.completed_at? %>
|
||||
<% if value.present? %>
|
||||
<% if (mask = field.dig('preferences', 'mask').presence) && signed_in? && can?(:read, @submission) %>
|
||||
<span class="group">
|
||||
@@ -320,6 +325,7 @@
|
||||
<% value = values[field['uuid']].presence || (field['default_value'] != '{{date}}' && field['readonly'] == true && field['default_value'].present? ? Submitters::SubmitValues.template_default_value_for_submitter(field['default_value'], @submission.submitters.find { |e| e.uuid == field['submitter_uuid'] }, with_time: false) : nil) %>
|
||||
<% next if value.blank? %>
|
||||
<% next if field['type'] == 'heading' || field['type'] == 'strikethrough' %>
|
||||
<% next if field['type'] == 'signature' && submitter && !submitter.completed_at? %>
|
||||
<div class="pt-2.5 border-b border-base-300">
|
||||
<div class="text-xs font-medium uppercase mb-0.5" dir="auto">
|
||||
<%= field['name'].presence || "#{t("#{field['type']}_field")} #{submitter_field_counters[field['type']]}" %>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<% last_submitter = @submission.submitters.completed.order(:completed_at).last %>
|
||||
<% if last_submitter %>
|
||||
<p dir="auto" class="text-sm">
|
||||
<%= t(last_submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(last_submitter.completed_at.to_date, format: :long)) %>
|
||||
<%= t(last_submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(last_submitter.completed_at.in_time_zone(@submission.account.timezone).to_date, format: :long)) %>
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div>
|
||||
<p dir="auto" class="text-lg font-bold mb-1"><%= @submitter.submission.name || @submitter.submission.template&.name %></p>
|
||||
<p dir="auto" class="text-sm">
|
||||
<%= t(@submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(completed_at.to_date, format: :long)) %>
|
||||
<%= t(@submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(completed_at.in_time_zone(@submitter.account.timezone).to_date, format: :long)) %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<div dir="auto">
|
||||
<p class="text-lg font-bold mb-1"><%= @submitter.submission.name || @submitter.submission.template&.name %></p>
|
||||
<p class="text-sm"><%= t('form_has_been_declined_on_html', time: l(@submitter.declined_at, format: :long)) %></p>
|
||||
<p class="text-sm"><%= t('form_has_been_declined_on_html', time: l(@submitter.declined_at.in_time_zone(@submitter.account.timezone).to_date, format: :long)) %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<div dir="auto">
|
||||
<p class="text-lg font-bold mb-1"><%= @submitter.submission.name || @submitter.submission.template&.name %></p>
|
||||
<p class="text-sm"><%= t('document_has_been_delegated_on_html', time: l(@submitter.submission_events.order(event_timestamp: :desc).find_by!(event_type: :delegate_form).event_timestamp, format: :long)) %></p>
|
||||
<p class="text-sm"><%= t('document_has_been_delegated_on_html', time: l(@submitter.submission_events.order(event_timestamp: :desc).find_by!(event_type: :delegate_form).event_timestamp.in_time_zone(@submitter.account.timezone).to_date, format: :long)) %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<% last_submitter = @submitter.submission.submitters.completed.order(:completed_at).last %>
|
||||
<% if last_submitter %>
|
||||
<p dir="auto" class="text-sm">
|
||||
<%= t(last_submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(last_submitter.completed_at.to_date, format: :long)) %>
|
||||
<%= t(last_submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(last_submitter.completed_at.in_time_zone(@submitter.account.timezone).to_date, format: :long)) %>
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<div dir="auto">
|
||||
<p class="text-lg font-bold mb-1"><%= @submitter.submission.name || @submitter.submission.template&.name %></p>
|
||||
<p class="text-sm"><%= t('form_expired_at_html', time: l(@submitter.submission.expire_at, format: :long)) %></p>
|
||||
<p class="text-sm"><%= t('form_expired_at_html', time: l(@submitter.submission.expire_at.in_time_zone(@submitter.account.timezone).to_date, format: :long)) %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+33
-12
@@ -704,6 +704,7 @@ en: &en
|
||||
developer_sandbox: Developer Sandbox.
|
||||
upgrade_to_start_using_in_production_html: '<a href="%{url}" target="_blank" class="link font-semibold">Upgrade</a> to start using in Production.'
|
||||
download_combined_pdf: Download combined PDF
|
||||
download_event_log: Download Event Log
|
||||
audit_log: Audit Log
|
||||
signers: Signers
|
||||
not_invited_yet: Not invited yet
|
||||
@@ -715,7 +716,7 @@ en: &en
|
||||
declined_on_time: 'Declined on %{time}'
|
||||
expire_on_time: 'Expire on %{time}'
|
||||
sign_in_person: Sign In-person
|
||||
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Create a new template</a> document form or <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">submit the existing one</a>
|
||||
create_a_new_template_document_form_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Create a new template</a> document form
|
||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Send email copy with completed documents to a specified BCC address.
|
||||
re_send_email: Re-send Email
|
||||
re_send_emails: Re-send Emails
|
||||
@@ -1027,6 +1028,8 @@ en: &en
|
||||
failed_to_scan_the_document: Failed to scan the document
|
||||
document_scanning_is_not_available_on_this_device: Document scanning is not available on this device
|
||||
click_to_upload: Click to upload
|
||||
cc_view_only: CC View-only
|
||||
bcc_completed: BCC Completed
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Your email address has been successfully confirmed.
|
||||
@@ -1862,6 +1865,7 @@ es: &es
|
||||
developer_sandbox: Sandbox para desarrolladores.
|
||||
upgrade_to_start_using_in_production_html: '<a href="%{url}" target="_blank" class="link font-semibold">Actualiza</a> para empezar a usar en Producción.'
|
||||
download_combined_pdf: Descargar PDF combinado
|
||||
download_event_log: Descargar registro de eventos
|
||||
audit_log: Registro de Auditoría
|
||||
signers: Firmantes
|
||||
not_invited_yet: Aún no invitado
|
||||
@@ -1873,7 +1877,7 @@ es: &es
|
||||
declined_on_time: 'Rechazado el %{time}'
|
||||
expire_on_time: 'Expira el %{time}'
|
||||
sign_in_person: Firma en persona
|
||||
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Crear una nueva plantilla</a> de documento o <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">enviar el existente</a>
|
||||
create_a_new_template_document_form_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Crear una nueva plantilla</a> de documento
|
||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Enviar una copia del correo electrónico con los documentos completados a una dirección BCC especificada.
|
||||
re_send_email: Reenviar email
|
||||
re_send_emails: Reenviar emails
|
||||
@@ -2174,6 +2178,8 @@ es: &es
|
||||
failed_to_save_the_scan: No se pudo guardar el escaneo
|
||||
failed_to_scan_the_document: No se pudo escanear el documento
|
||||
document_scanning_is_not_available_on_this_device: El escaneo de documentos no está disponible en este dispositivo
|
||||
cc_view_only: CC Solo lectura
|
||||
bcc_completed: CCO Completado
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente.
|
||||
@@ -3023,6 +3029,7 @@ it: &it
|
||||
developer_sandbox: Sandbox per sviluppatori
|
||||
upgrade_to_start_using_in_production_html: '<a href="%{url}" target="_blank" class="link font-semibold">Aggiorna</a> per iniziare a usare in produzione.'
|
||||
download_combined_pdf: Scarica PDF combinato
|
||||
download_event_log: Scarica registro degli eventi
|
||||
audit_log: Registro di audit
|
||||
signers: Firmatari
|
||||
not_invited_yet: Non ancora invitato
|
||||
@@ -3034,7 +3041,7 @@ it: &it
|
||||
declined_on_time: 'Rifiutato il %{time}'
|
||||
expire_on_time: 'Scade il %{time}'
|
||||
sign_in_person: Firma di persona
|
||||
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Crea un nuovo modello</a> di documento o <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">invia quello esistente</a>
|
||||
create_a_new_template_document_form_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Crea un nuovo modello</a> di documento
|
||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Invia una copia dell'email con i documenti completati a un indirizzo BCC specificato.
|
||||
re_send_email: Reinvia email
|
||||
re_send_emails: Reinvia le email
|
||||
@@ -3335,6 +3342,8 @@ it: &it
|
||||
failed_to_save_the_scan: Impossibile salvare la scansione
|
||||
failed_to_scan_the_document: Impossibile scansionare il documento
|
||||
document_scanning_is_not_available_on_this_device: La scansione dei documenti non è disponibile su questo dispositivo
|
||||
cc_view_only: CC Sola lettura
|
||||
bcc_completed: BCC Completato
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Il tuo indirizzo email è stato confermato con successo.
|
||||
@@ -4170,6 +4179,7 @@ fr: &fr
|
||||
developer_sandbox: Bac à sable développeur.
|
||||
upgrade_to_start_using_in_production_html: <a href="%{url}" target="_blank" class="link font-semibold">Mettez à niveau</a> pour commencer à utiliser en production.
|
||||
download_combined_pdf: Télécharger le PDF combiné
|
||||
download_event_log: Télécharger le journal des événements
|
||||
audit_log: Journal d’audit
|
||||
signers: Signataires
|
||||
not_invited_yet: Pas encore invité
|
||||
@@ -4181,7 +4191,7 @@ fr: &fr
|
||||
declined_on_time: Refusé le %{time}
|
||||
expire_on_time: Expire le %{time}
|
||||
sign_in_person: Signer en personne
|
||||
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Créez un nouveau modèle</a> de document ou <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">soumettez l’existant</a>
|
||||
create_a_new_template_document_form_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Créez un nouveau modèle</a> de document
|
||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Envoyer une copie e‑mail avec les documents complétés à une adresse Cci spécifiée.
|
||||
re_send_email: Renvoyer l’e‑mail
|
||||
re_send_emails: Renvoyer e‑mails
|
||||
@@ -4479,6 +4489,8 @@ fr: &fr
|
||||
failed_to_save_the_scan: Impossible d’enregistrer la numérisation
|
||||
failed_to_scan_the_document: Impossible de numériser le document
|
||||
document_scanning_is_not_available_on_this_device: La numérisation de documents n’est pas disponible sur cet appareil
|
||||
cc_view_only: Cc Lecture seule
|
||||
bcc_completed: Cci Terminé
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Votre adresse e-mail a été confirmée avec succès.
|
||||
@@ -5327,6 +5339,7 @@ pt: &pt
|
||||
developer_sandbox: Sandbox para desenvolvedores
|
||||
upgrade_to_start_using_in_production_html: '<a href="%{url}" target="_blank" class="link font-semibold">Atualizar</a> para começar a usar em produção.'
|
||||
download_combined_pdf: Baixar PDF combinado
|
||||
download_event_log: Baixar log de eventos
|
||||
audit_log: Log de auditoria
|
||||
signers: Signatários
|
||||
not_invited_yet: Ainda não convidado
|
||||
@@ -5338,7 +5351,7 @@ pt: &pt
|
||||
declined_on_time: 'Recusado em %{time}'
|
||||
expire_on_time: 'Expira em %{time}'
|
||||
sign_in_person: Assinar pessoalmente
|
||||
create_a_new_template_document_form_or_submit_the_existing_one_html: '<a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Criar um novo modelo</a> de documento ou <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">submeter o existente</a>'
|
||||
create_a_new_template_document_form_html: '<a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Criar um novo modelo</a> de documento'
|
||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Envie uma cópia do e-mail com documentos concluídos para um endereço BCC especificado.
|
||||
re_send_email: Reenviar e-mail
|
||||
re_send_emails: Reenviar e-mails
|
||||
@@ -5639,6 +5652,8 @@ pt: &pt
|
||||
failed_to_save_the_scan: Não foi possível salvar a digitalização
|
||||
failed_to_scan_the_document: Não foi possível digitalizar o documento
|
||||
document_scanning_is_not_available_on_this_device: A digitalização de documentos não está disponível neste dispositivo
|
||||
cc_view_only: CC Somente leitura
|
||||
bcc_completed: BCC Concluído
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Seu endereço de e-mail foi confirmado com sucesso.
|
||||
@@ -6487,6 +6502,7 @@ de: &de
|
||||
developer_sandbox: Entwickler-Sandbox.
|
||||
upgrade_to_start_using_in_production_html: '<a href="%{url}" target="_blank" class="link font-semibold">Upgrade</a> durchführen, um die Produktionsnutzung zu starten.'
|
||||
download_combined_pdf: Kombiniertes PDF herunterladen
|
||||
download_event_log: Ereignisprotokoll herunterladen
|
||||
audit_log: Prüfprotokoll
|
||||
signers: Unterzeichner
|
||||
not_invited_yet: Noch nicht eingeladen
|
||||
@@ -6498,7 +6514,7 @@ de: &de
|
||||
declined_on_time: 'Abgelehnt am %{time}'
|
||||
expire_on_time: 'Läuft ab am %{time}'
|
||||
sign_in_person: Vor Ort unterschreiben
|
||||
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Neue Vorlage erstellen</a> oder <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">bestehende einreichen</a>
|
||||
create_a_new_template_document_form_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Neue Vorlage erstellen</a>
|
||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Senden Sie eine E-Mail-Kopie mit abgeschlossenen Dokumenten an eine angegebene BCC-Adresse.
|
||||
re_send_email: E-Mail erneut senden
|
||||
re_send_emails: E-Mails senden
|
||||
@@ -6799,6 +6815,8 @@ de: &de
|
||||
failed_to_save_the_scan: Scan konnte nicht gespeichert werden
|
||||
failed_to_scan_the_document: Dokument konnte nicht gescannt werden
|
||||
document_scanning_is_not_available_on_this_device: Das Scannen von Dokumenten ist auf diesem Gerät nicht verfügbar
|
||||
cc_view_only: CC Nur Ansicht
|
||||
bcc_completed: BCC Abgeschlossen
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt.
|
||||
@@ -6981,14 +6999,14 @@ pl:
|
||||
decline_reason: Powód odrzucenia
|
||||
provide_a_reason: Podaj powód
|
||||
notify_the_sender_with_the_reason_you_declined: Powiadom nadawcę o powodzie, dla którego odrzuciłeś
|
||||
form_has_been_declined_on_html: 'Formularz został odrzucony o <span class="font-semibold">%{time}</span>'
|
||||
document_has_been_delegated_on_html: 'Dokument został oddelegowany o <span class="font-semibold">%{time}</span>'
|
||||
form_has_been_declined_on_html: 'Formularz został odrzucony <span class="font-semibold">%{time}</span>'
|
||||
document_has_been_delegated_on_html: 'Dokument został oddelegowany <span class="font-semibold">%{time}</span>'
|
||||
name_declined_by_submitter: '"%{name}" odrzucono przez %{submitter}'
|
||||
name_declined_by_submitter_with_the_following_reason: '"%{name}" został odrzucony przez %{submitter} z następującym powodem:'
|
||||
email: E-mail
|
||||
verification_code_code: 'Kod weryfikacyjny: %{code}'
|
||||
digitally_signed_by: Podpis cyfrowy przez
|
||||
form_expired_at_html: 'Formularz wygasł o <span class="font-semibold">%{time}</span>'
|
||||
form_expired_at_html: 'Formularz wygasł <span class="font-semibold">%{time}</span>'
|
||||
role: Rola
|
||||
provide_your_email_to_start: Podaj swój e-mail, aby rozpocząć
|
||||
provide_your_email: Podaj swój e-mail
|
||||
@@ -7123,8 +7141,8 @@ uk:
|
||||
decline_reason: Причина відхилення
|
||||
provide_a_reason: Надайте причину
|
||||
notify_the_sender_with_the_reason_you_declined: Повідомте відправника про причину свого відхилення
|
||||
form_has_been_declined_on_html: 'Форму було відхилено о <span class="font-semibold">%{time}</span>'
|
||||
document_has_been_delegated_on_html: 'Документ було делеговано о <span class="font-semibold">%{time}</span>'
|
||||
form_has_been_declined_on_html: 'Форму було відхилено <span class="font-semibold">%{time}</span>'
|
||||
document_has_been_delegated_on_html: 'Документ було делеговано <span class="font-semibold">%{time}</span>'
|
||||
name_declined_by_submitter: '"%{name}" відхилено %{submitter}'
|
||||
name_declined_by_submitter_with_the_following_reason: '"%{name}" було відхилено %{submitter} з такою причиною:'
|
||||
email: E-mail
|
||||
@@ -8175,6 +8193,7 @@ nl: &nl
|
||||
developer_sandbox: Ontwikkelaars-sandbox.
|
||||
upgrade_to_start_using_in_production_html: <a href="%{url}" target="_blank" class="link font-semibold">Upgrade</a> om in productie te gaan gebruiken.
|
||||
download_combined_pdf: Gecombineerde PDF downloaden
|
||||
download_event_log: Gebeurtenislogboek downloaden
|
||||
audit_log: Auditlogboek
|
||||
signers: Ondertekenaars
|
||||
not_invited_yet: Nog niet uitgenodigd
|
||||
@@ -8186,7 +8205,7 @@ nl: &nl
|
||||
declined_on_time: Geweigerd op %{time}
|
||||
expire_on_time: Verloopt op %{time}
|
||||
sign_in_person: In persoon ondertekenen
|
||||
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Maak een nieuw sjabloon</a> voor een documentformulier of <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">dien het bestaande in</a>
|
||||
create_a_new_template_document_form_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Maak een nieuw sjabloon</a> voor een documentformulier
|
||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Stuur een e-mailkopie met voltooide documenten naar een opgegeven BCC-adres.
|
||||
re_send_email: E-mail opnieuw verzenden
|
||||
re_send_emails: E-mails verzenden
|
||||
@@ -8483,6 +8502,8 @@ nl: &nl
|
||||
failed_to_save_the_scan: Scan kon niet worden opgeslagen
|
||||
failed_to_scan_the_document: Document kon niet worden gescand
|
||||
document_scanning_is_not_available_on_this_device: Documenten scannen is niet beschikbaar op dit apparaat
|
||||
cc_view_only: CC Alleen bekijken
|
||||
bcc_completed: BCC Voltooid
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Uw e-mailadres is succesvol bevestigd.
|
||||
|
||||
@@ -5,34 +5,6 @@ module Accounts
|
||||
|
||||
module_function
|
||||
|
||||
def create_duplicate(account)
|
||||
new_account = account.dup
|
||||
|
||||
new_user = account.users.first.dup
|
||||
|
||||
new_user.uuid = SecureRandom.uuid
|
||||
new_user.account = new_account
|
||||
new_user.encrypted_password = SecureRandom.hex
|
||||
new_user.email = "#{SecureRandom.hex}@docuseal.com"
|
||||
|
||||
account.templates.each do |template|
|
||||
new_template = template.dup
|
||||
|
||||
new_template.account = new_account
|
||||
new_template.slug = SecureRandom.base58(14)
|
||||
|
||||
new_template.archived_at = nil
|
||||
new_template.save!
|
||||
|
||||
Templates::CloneAttachments.call(template: new_template, original_template: template)
|
||||
end
|
||||
|
||||
new_user.save!(validate: false)
|
||||
new_account.templates.update_all(folder_id: new_account.default_template_folder.id)
|
||||
|
||||
new_account
|
||||
end
|
||||
|
||||
def users_count(account)
|
||||
rel = User.where(account_id: account.id).or(
|
||||
User.where(account_id: account.account_linked_accounts
|
||||
|
||||
@@ -90,6 +90,10 @@ module Submissions
|
||||
|
||||
maybe_add_invite_submitters(submission, template, attrs[:submitters])
|
||||
|
||||
maybe_add_cc_submitters(submission, params[:cc_recipients],
|
||||
submitters_order:, user:, params:,
|
||||
preferences: preferences.merge(submission_preferences))
|
||||
|
||||
assign_submitters_is_viewer(submission)
|
||||
|
||||
submission.template = nil unless with_template
|
||||
@@ -211,6 +215,25 @@ module Submissions
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_add_cc_submitters(submission, recipients, submitters_order:, user:, params:, preferences:)
|
||||
order = submission.template_submitters.filter_map { |s| s['order'] }.max
|
||||
|
||||
Array.wrap(recipients).each do |recipient|
|
||||
attrs = recipient.is_a?(String) ? { email: recipient } : recipient.slice(:name, :email, :phone)
|
||||
|
||||
next if attrs.compact_blank.blank?
|
||||
|
||||
uuid = SecureRandom.uuid
|
||||
|
||||
submission.template_submitters <<
|
||||
{ 'name' => 'CC', 'uuid' => uuid, 'is_viewer' => true, 'order' => order }.compact
|
||||
|
||||
build_submitter(submission:, attrs:, uuid:, user:, params:,
|
||||
is_order_sent: submitters_order == 'random',
|
||||
preferences: preferences.except('email_message_uuid'))
|
||||
end
|
||||
end
|
||||
|
||||
def submitter_message_preferences(uuid, params)
|
||||
return {} if params[:request_email_per_submitter] != '1'
|
||||
return {} if params[:is_custom_message] != '1'
|
||||
|
||||
+9
-1
@@ -152,7 +152,7 @@ module Submitters
|
||||
preferences['send_sms'] = params['send_sms'].in?(TRUE_VALUES) if params.key?('send_sms')
|
||||
preferences['require_phone_2fa'] = params['require_phone_2fa'].in?(TRUE_VALUES) if params.key?('require_phone_2fa')
|
||||
preferences['require_email_2fa'] = params['require_email_2fa'].in?(TRUE_VALUES) if params.key?('require_email_2fa')
|
||||
preferences['bcc_completed'] = params['bcc_completed'] if params.key?('bcc_completed')
|
||||
preferences['bcc_completed'] = normalize_bcc_completed(params['bcc_completed']) if params.key?('bcc_completed')
|
||||
preferences['reply_to'] = params['reply_to'] if params.key?('reply_to')
|
||||
preferences['go_to_last'] = params['go_to_last'] if params.key?('go_to_last')
|
||||
preferences['completed_redirect_url'] = params['completed_redirect_url'] if params.key?('completed_redirect_url')
|
||||
@@ -160,6 +160,14 @@ module Submitters
|
||||
preferences
|
||||
end
|
||||
|
||||
def normalize_bcc_completed(value)
|
||||
if value.is_a?(Array)
|
||||
value.compact_blank.uniq.join(', ')
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_values_for_delegate(submitter)
|
||||
fields = submitter.submission.template_fields || submitter.template.fields
|
||||
default_values = submitter.preferences['default_values'] || {}
|
||||
|
||||
@@ -90,23 +90,28 @@ module Templates
|
||||
|
||||
pool = Concurrent::FixedThreadPool.new(concurrency)
|
||||
|
||||
promises =
|
||||
range.map do |page_number|
|
||||
doc_page = doc.get_page(page_number)
|
||||
blobs =
|
||||
range.each_slice(concurrency).flat_map do |page_numbers|
|
||||
promises =
|
||||
page_numbers.map do |page_number|
|
||||
doc_page = doc.get_page(page_number)
|
||||
|
||||
hide_placeholder_widgets(doc_page, hide_empty: !flatten_pages)
|
||||
doc_page.flatten if flatten_pages
|
||||
hide_placeholder_widgets(doc_page, hide_empty: !flatten_pages)
|
||||
doc_page.flatten if flatten_pages
|
||||
|
||||
bytes, width, height = doc_page.render_to_bitmap(width: MAX_WIDTH)
|
||||
bytes, width, height = doc_page.render_to_bitmap(width: MAX_WIDTH)
|
||||
|
||||
image = Vips::Image.new_from_memory_copy(bytes, width, height, 4, :uchar)
|
||||
image = Vips::Image.new_from_memory_copy(bytes, width, height, 4, :uchar)
|
||||
|
||||
Concurrent::Promise.execute(executor: pool) { build_and_upload_blob(image, page_number) }
|
||||
ensure
|
||||
doc_page&.close
|
||||
Concurrent::Promise.execute(executor: pool) { build_and_upload_blob(image, page_number) }
|
||||
ensure
|
||||
doc_page&.close
|
||||
end
|
||||
|
||||
Concurrent::Promise.zip(*promises).value!
|
||||
end
|
||||
|
||||
Concurrent::Promise.zip(*promises).value!.each do |blob|
|
||||
blobs.each do |blob|
|
||||
next unless blob
|
||||
|
||||
ApplicationRecord.no_touching do
|
||||
|
||||
Reference in new issue
Block a user