diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a99e0796f..f7e74b9b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - name: Install Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 4.0.5 + ruby-version: 4.0.9 - name: Cache gems uses: actions/cache@v4 with: @@ -37,7 +37,7 @@ jobs: - name: Install Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 4.0.5 + ruby-version: 4.0.9 - name: Cache gems uses: actions/cache@v4 with: @@ -89,7 +89,7 @@ jobs: - name: Install Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 4.0.5 + ruby-version: 4.0.9 - name: Cache gems uses: actions/cache@v4 with: @@ -113,7 +113,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 container: - image: ruby:4.0.5-alpine + image: ruby:4.0.9-alpine services: postgres: diff --git a/Dockerfile b/Dockerfile index e7d53cf8b..afb53882b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0.5-alpine AS download +FROM ruby:4.0.9-alpine AS download WORKDIR /fonts @@ -17,7 +17,7 @@ RUN apk --no-cache add wget unzip && \ mkdir -p /pdfium-linux && \ unzip -q pdfium-linux.zip -d /pdfium-linux -FROM ruby:4.0.5-alpine AS webpack +FROM ruby:4.0.9-alpine AS webpack ENV RAILS_ENV=production ENV NODE_ENV=production @@ -44,7 +44,7 @@ COPY ./app/views ./app/views RUN echo "gem 'shakapacker'" > Gemfile && ./bin/shakapacker -FROM ruby:4.0.5-alpine AS app +FROM ruby:4.0.9-alpine AS app ENV RAILS_ENV=production ENV BUNDLE_WITHOUT="development:test" @@ -52,7 +52,8 @@ ENV OPENSSL_CONF=/etc/openssl_legacy.cnf WORKDIR /app -RUN apk add --no-cache libpq vips redis onnxruntime leptonica jemalloc font-liberation font-carlito && \ +RUN apk upgrade --no-cache ca-certificates-bundle && \ + apk add --no-cache libpq vips redis onnxruntime leptonica jemalloc font-liberation font-carlito && \ rm -f /usr/bin/onnx_test_runner /usr/bin/onnxruntime_test RUN addgroup -g 2000 docuseal && adduser -u 2000 -G docuseal -s /bin/sh -D -h /home/docuseal docuseal diff --git a/Gemfile b/Gemfile index fc482901b..86f3c0856 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' -ruby '4.0.5' +ruby '4.0.9' gem 'addressable' gem 'arabic-letter-connector', require: false diff --git a/Gemfile.lock b/Gemfile.lock index ee3d8e886..8a83f4cb3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -572,15 +572,15 @@ GEM base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - wordcraft (0.8.0-aarch64-linux-gnu) + wordcraft (0.11.0-aarch64-linux-gnu) ffi (>= 1.15) - wordcraft (0.8.0-aarch64-linux-musl) + wordcraft (0.11.0-aarch64-linux-musl) ffi (>= 1.15) - wordcraft (0.8.0-arm64-darwin) + wordcraft (0.11.0-arm64-darwin) ffi (>= 1.15) - wordcraft (0.8.0-x86_64-linux-gnu) + wordcraft (0.11.0-x86_64-linux-gnu) ffi (>= 1.15) - wordcraft (0.8.0-x86_64-linux-musl) + wordcraft (0.11.0-x86_64-linux-musl) ffi (>= 1.15) xlsxtream (3.1.0) zip_kit (>= 6.2, < 7) @@ -664,7 +664,7 @@ DEPENDENCIES xlsxtream RUBY VERSION - ruby 4.0.5 + ruby 4.0.9 BUNDLED WITH 4.0.3 diff --git a/app/controllers/api/attachments_controller.rb b/app/controllers/api/attachments_controller.rb deleted file mode 100644 index 95c3f6c18..000000000 --- a/app/controllers/api/attachments_controller.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -module Api - class AttachmentsController < ActionController::API - include ActionController::Cookies - include ActiveStorage::SetCurrent - - COOKIE_STORE_LIMIT = 10 - - def create - @submitter = Submitter.find_by!(slug: params[:submitter_slug]) - - unless can_upload?(@submitter) - return render json: { error: I18n.t('form_has_been_archived') }, status: :unprocessable_content - end - - file = params[:file] - - if params[:type].in?(%w[initials signature]) - image = ImageUtils.load_vips(file.read, content_type: file.content_type) - - if ImageUtils.blank?(image) - Rollbar.error("Empty signature: #{@submitter.id}") if defined?(Rollbar) - - return render json: { error: "#{params[:type]} is empty" }, status: :unprocessable_content - end - - if ImageUtils.error?(image) - Rollbar.error("Error signature: #{@submitter.id}") if defined?(Rollbar) - - return render json: { error: "#{params[:type]} error, try to sign on another device" }, - status: :unprocessable_content - end - - metadata = { analyzed: true, identified: true, width: image.width, height: image.height } - end - - attachment = Submitters.create_attachment!(@submitter, file, metadata:) - - if params[:remember_signature] == 'true' && @submitter.email.present? - cookies.permanent.encrypted[:signature_uuids] = build_new_cookie_signatures_json(@submitter, attachment) - end - - render json: attachment.as_json(only: %i[uuid created_at], methods: %i[url filename content_type]) - rescue Submitters::MaliciousFileExtension => e - Rollbar.error(e) if defined?(Rollbar) - - render json: { error: e.message }, status: :unprocessable_content - end - - def can_upload?(submitter) - !submitter.declined_at? && - !submitter.completed_at? && - !submitter.submission.archived_at? && - !submitter.submission.expired? && - !submitter.submission.template&.archived_at? - end - - def build_new_cookie_signatures_json(submitter, attachment) - values = - begin - JSON.parse(cookies.encrypted[:signature_uuids].presence || '{}') - rescue JSON::ParserError - {} - end - - values[submitter.email] = attachment.uuid - - values = values.to_a.last(COOKIE_STORE_LIMIT).to_h if values.size > COOKIE_STORE_LIMIT - - values.to_json - end - end -end diff --git a/app/controllers/api/submitter_email_clicks_controller.rb b/app/controllers/api/submitter_email_clicks_controller.rb deleted file mode 100644 index 9c52fc5b6..000000000 --- a/app/controllers/api/submitter_email_clicks_controller.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module Api - class SubmitterEmailClicksController < ActionController::API - def create - @submitter = Submitter.find_by!(slug: params[:submitter_slug]) - - if params[:t] == SubmissionEvents.build_tracking_param(@submitter, 'click_email') - SubmissionEvents.create_with_tracking_data(@submitter, 'click_email', request) - end - - render json: {} - end - end -end diff --git a/app/controllers/api/submitters_controller.rb b/app/controllers/api/submitters_controller.rb index 313f84fc1..a547ba75a 100644 --- a/app/controllers/api/submitters_controller.rb +++ b/app/controllers/api/submitters_controller.rb @@ -179,10 +179,7 @@ module Api submitters = submitters.where(external_id: params[:external_id]) if params[:external_id].present? submitters = submitters.where(slug: params[:slug]) if params[:slug].present? submitters = submitters.where(submission_id: params[:submission_id]) if params[:submission_id].present? - - if params[:template_id].present? - submitters = submitters.joins(:submission).where(submissions: { template_id: params[:template_id] }) - end + submitters = submitters.where(template_id: params[:template_id]) if params[:template_id].present? maybe_filter_by_completed_at(submitters, params) end diff --git a/app/javascript/application.js b/app/javascript/application.js index a08c858a4..5db6cce6e 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -228,6 +228,7 @@ safeRegisterElement('template-builder', class extends HTMLElement { template, customFields: reactive(JSON.parse(this.dataset.customFields || '[]')), dateFormats: JSON.parse(this.dataset.dateFormats || '[]'), + autosave: this.dataset.autosave !== 'false', dynamicDocuments: reactive(JSON.parse(this.dataset.dynamicDocuments || '[]')), backgroundColor: '#faf7f5', locale: this.dataset.locale, diff --git a/app/javascript/elements/toggle_send_title.js b/app/javascript/elements/toggle_send_title.js index 5d73e7706..4dc54aec7 100644 --- a/app/javascript/elements/toggle_send_title.js +++ b/app/javascript/elements/toggle_send_title.js @@ -12,7 +12,14 @@ export default class extends HTMLElement { toggle = (event) => { if (event?.type === 'input' && event.target.matches(this.fieldSelector('name'))) return - const isNameOnly = (field) => this.isFilled('name') && !this.isFilled(field) + if (event?.type === 'focusin' && !this.isKeepSendUsed && this.isFocusFromName(event)) { + this.isKeepSendUsed = true + this.keepSendInput = event.target + } else if (event?.type === 'focusout' && event.target === this.keepSendInput) { + this.keepSendInput = null + } + + const isNameOnly = (field) => this.isFilled('name') && !this.isFilled(field) && !this.keepSendInput?.matches(this.fieldSelector(field)) const isSend = (this.isChecked('send_email') && !isNameOnly('email')) || (this.isChecked('send_sms') && !isNameOnly('phone')) @@ -29,12 +36,17 @@ export default class extends HTMLElement { return [...this.form.querySelectorAll(this.fieldSelector(field))].some((input) => input.value.trim()) } + isFocusFromName ({ target, relatedTarget }) { + return !!relatedTarget?.matches(this.fieldSelector('name')) && !!relatedTarget.value.trim() && + ['email', 'phone'].some((field) => target.matches(this.fieldSelector(field))) + } + fieldSelector (field) { return `[name$="[][${field}]"]` } get events () { - return ['change', 'input', 'linked-input.update'] + return ['change', 'input', 'linked-input.update', 'focusin', 'focusout'] } get form () { diff --git a/app/javascript/template_builder/builder.vue b/app/javascript/template_builder/builder.vue index f8c2580bc..620ab845a 100644 --- a/app/javascript/template_builder/builder.vue +++ b/app/javascript/template_builder/builder.vue @@ -415,9 +415,9 @@ { if (document.location.search?.includes('stripe_connect_success')) { document.querySelector('form[action="/auth/stripe_connect"]')?.closest('.dropdown')?.querySelector('label')?.focus() @@ -1685,6 +1692,11 @@ export default { this.resizeObserver.disconnect() window.removeEventListener('dragleave', this.onWindowDragLeave) + + if (!this.autosave) { + window.removeEventListener('beforeunload', this.onBeforeUnload) + document.removeEventListener('turbo:before-visit', this.onBeforeVisit) + } }, beforeUpdate () { this.documentRefs = [] @@ -2241,6 +2253,37 @@ export default { this.insertField(field) } }, + onSaveAndPreviewClick (event) { + this.isPreviewLoading = true + + if (!this.autosave) { + event.preventDefault() + + const dynamicDocumentRefs = this.documentRefs.filter((ref) => ref.isDynamic) + + dynamicDocumentRefs.forEach((ref) => ref.update()) + + this.rebuildVariablesSchema({ disable: false }) + + Promise.all([this.save({ force: true }), ...dynamicDocumentRefs.map((ref) => ref.saveBody())]).then(() => { + window.Turbo.visit(`/templates/${this.template.id}/form`) + }) + } + }, + onBeforeUnload (event) { + if (this.hasUnsavedChanges) { + event.preventDefault() + + event.returnValue = '' + + return '' + } + }, + onBeforeVisit (event) { + if (this.hasUnsavedChanges && !window.confirm(this.t('close_without_saving_changes'))) { + event.preventDefault() + } + }, closeDropdown () { document.activeElement.blur() }, @@ -4036,6 +4079,8 @@ export default { } if (!this.autosave && !force) { + this.hasUnsavedChanges = true + return Promise.resolve({}) } @@ -4058,6 +4103,8 @@ export default { }), headers: { 'Content-Type': 'application/json' } }).then(() => { + this.hasUnsavedChanges = false + if (this.onSave) { this.onSave(this.template) } diff --git a/app/javascript/template_builder/dynamic_document.vue b/app/javascript/template_builder/dynamic_document.vue index 3391e8223..eabebe8be 100644 --- a/app/javascript/template_builder/dynamic_document.vue +++ b/app/javascript/template_builder/dynamic_document.vue @@ -84,6 +84,11 @@ export default { required: false, default: true }, + autosave: { + type: Boolean, + required: false, + default: true + }, selectedSubmitter: { type: Object, required: false, @@ -279,7 +284,7 @@ export default { this.updatedSectionEditors.set(section.id, editor) - this.saveTimer = setTimeout(() => this.updateSectionsAndSave(), 1000) + this.saveTimer = setTimeout(() => this.autosave ? this.updateSectionsAndSave() : this.updateSections(), 1000) }, loadListsStyle () { this.listsStyle = this.bodyDom.querySelector('body > style[data-lists]')?.textContent || null @@ -299,7 +304,9 @@ export default { updateVariablesSchema () { this.document.variables_schema = buildVariablesSchema(this.bodyDom.body) }, - updateSectionsAndSave () { + updateSections () { + delete this.saveTimer + this.updatedSectionEditors.forEach((editor, sectionId) => { const target = this.bodyDom.getElementById(sectionId) @@ -315,6 +322,9 @@ export default { this.updateVariablesSchema() this.$emit('update', this.document) + }, + updateSectionsAndSave () { + this.updateSections() return this.saveBody() }, diff --git a/app/javascript/template_builder/i18n.js b/app/javascript/template_builder/i18n.js index a377ba2f3..6a0466340 100644 --- a/app/javascript/template_builder/i18n.js +++ b/app/javascript/template_builder/i18n.js @@ -70,6 +70,7 @@ const en = { remove_condition: 'Remove condition', add_condition: 'Add condition', are_you_sure_: 'Are you sure?', + close_without_saving_changes: 'Close without saving changes?', sign_yourself: 'Sign Yourself', set_signing_date: 'Set signing date', signing_date: 'Signing Date', @@ -371,6 +372,7 @@ const es = { down: 'Abajo', set_signing_date: 'Establecer fecha de firma', are_you_sure_: '¿Estás seguro?', + close_without_saving_changes: '¿Cerrar sin guardar los cambios?', sign_yourself: 'Firma tú mismo', checked: 'Marcado', current_date: 'Fecha actual', @@ -652,6 +654,7 @@ const it = { remove_condition: 'Rimuovi condizione', add_condition: 'Aggiungi condizione', are_you_sure_: 'Sei sicuro?', + close_without_saving_changes: 'Chiudere senza salvare le modifiche?', sign_yourself: 'Firma te stesso', set_signing_date: 'Imposta data di firma', signing_date: 'Data di firma', @@ -953,6 +956,7 @@ const pt = { down: 'Para baixo', set_signing_date: 'Definir data de assinatura', are_you_sure_: 'Tem certeza?', + close_without_saving_changes: 'Fechar sem salvar as alterações?', sign_yourself: 'Assine você mesmo', checked: 'Marcado', current_date: 'Data atual', @@ -1234,6 +1238,7 @@ const fr = { remove_condition: 'Supprimer la condition', add_condition: 'Ajouter une condition', are_you_sure_: 'Êtes-vous sûr ?', + close_without_saving_changes: 'Fermer sans enregistrer les modifications ?', sign_yourself: 'Signer vous-même', set_signing_date: 'Définir la date de signature', signing_date: 'Date de signature', @@ -1525,6 +1530,7 @@ const de = { remove_condition: 'Bedingung entfernen', add_condition: 'Bedingung hinzufügen', are_you_sure_: 'Sind Sie sicher?', + close_without_saving_changes: 'Ohne Speichern der Änderungen schließen?', sign_yourself: 'Selbst unterschreiben', set_signing_date: 'Unterzeichnungsdatum festlegen', signing_date: 'Unterzeichnungsdatum', @@ -1816,6 +1822,7 @@ const nl = { remove_condition: 'Voorwaarde verwijderen', add_condition: 'Voorwaarde toevoegen', are_you_sure_: 'Weet u het zeker?', + close_without_saving_changes: 'Sluiten zonder wijzigingen op te slaan?', sign_yourself: 'Zelf ondertekenen', set_signing_date: 'Ondertekeningsdatum instellen', signing_date: 'Ondertekeningsdatum', diff --git a/app/jobs/send_test_webhook_request_job.rb b/app/jobs/send_test_webhook_request_job.rb index 0116cdafb..6b14769d6 100644 --- a/app/jobs/send_test_webhook_request_job.rb +++ b/app/jobs/send_test_webhook_request_job.rb @@ -30,14 +30,16 @@ class SendTestWebhookRequestJob raise LocalhostError, "Can't send to localhost." if uri.host.in?(SendWebhookRequest::LOCALHOSTS) end - Faraday.post(webhook_url.url, - { - event_type: 'form.completed', - timestamp: Time.current.iso8601, - data: Submitters::SerializeForWebhook.call(submitter) - }.to_json, + body_json = { + event_type: 'form.completed', + timestamp: Time.current.iso8601, + data: Submitters::SerializeForWebhook.call(submitter) + }.to_json + + Faraday.post(webhook_url.url, body_json, 'Content-Type' => 'application/json', 'User-Agent' => USER_AGENT, + 'X-Docuseal-Signature' => WebhookUrls::Signatures.sign(webhook_url.hmac_secret, body: body_json), **webhook_url.secret.to_h) end end diff --git a/app/models/account_config.rb b/app/models/account_config.rb index fa6d89b7a..fbc092646 100644 --- a/app/models/account_config.rb +++ b/app/models/account_config.rb @@ -61,6 +61,7 @@ class AccountConfig < ApplicationRecord DOCUMENT_FILENAME_FORMAT_KEY = 'document_filename_format' TEMPLATE_CUSTOM_FIELDS_KEY = 'template_custom_fields' TEMPLATE_DATE_FORMATS_KEY = 'template_date_formats' + TEMPLATE_BUILDER_AUTOSAVE_KEY = 'template_builder_autosave' POLICY_LINKS_KEY = 'policy_links' ENABLE_MCP_KEY = 'enable_mcp' diff --git a/app/models/submitter.rb b/app/models/submitter.rb index 0a7f70b8f..f3cdfd107 100644 --- a/app/models/submitter.rb +++ b/app/models/submitter.rb @@ -25,15 +25,17 @@ # account_id :bigint not null # external_id :string # submission_id :bigint not null +# template_id :bigint # # Indexes # # index_submitters_on_account_id_and_completed_at (account_id,completed_at) WHERE (completed_at IS NOT NULL) # index_submitters_on_account_id_and_id (account_id,id) -# index_submitters_on_email (email) +# index_submitters_on_email_and_template_id (email,template_id) WHERE (email IS NOT NULL) # index_submitters_on_external_id (external_id) # index_submitters_on_slug (slug) UNIQUE # index_submitters_on_submission_id (submission_id) +# index_submitters_on_template_id_and_id (template_id,id) # # Foreign Keys # @@ -68,6 +70,8 @@ class Submitter < ApplicationRecord scope :completed, -> { where.not(completed_at: nil) } + before_validation :set_template_id, on: :create + after_destroy :anonymize_email_events, if: -> { Docuseal.multitenant? } def status @@ -124,6 +128,10 @@ class Submitter < ApplicationRecord private + def set_template_id + self.template_id = submission&.template_id + end + def anonymize_email_events email_events.each do |event| event.update!(email: Digest::MD5.base64digest(event.email)) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index cf5afe1a8..a2beb0461 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -33,10 +33,10 @@ <% end %> <%= render turbo_native_app? ? 'shared/native_navbar' : 'shared/navbar' %> - <% if flash.present? %><%= render 'shared/flash' %><% end %> -
+
<%= yield %> -
+ + <% if flash.present? %><%= render 'shared/flash' %><% end %> <%= render 'shared/body_scripts' %> diff --git a/app/views/layouts/form.html.erb b/app/views/layouts/form.html.erb index 400b0bd9a..f74a29055 100644 --- a/app/views/layouts/form.html.erb +++ b/app/views/layouts/form.html.erb @@ -13,6 +13,8 @@ <%= stylesheet_pack_tag 'form', media: 'all', data: { turbo_track: 'dynamic' } %> - <%= yield %> +
+ <%= yield %> +
diff --git a/app/views/layouts/plain.html.erb b/app/views/layouts/plain.html.erb index f23f9b267..6c2f5fe8b 100644 --- a/app/views/layouts/plain.html.erb +++ b/app/views/layouts/plain.html.erb @@ -13,8 +13,10 @@ <%= stylesheet_pack_tag 'application', media: 'all', data: { turbo_track: 'dynamic' } %> - <% if flash.present? %><%= render 'shared/flash' %><% end %> - <%= yield %> +
+ <%= yield %> +
+ <% if flash.present? %><%= render 'shared/flash' %><% end %> diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index f44a3dac3..36e165dc8 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -1,5 +1,5 @@ <%= render 'shared/navbar_warning' %> -
+
+ diff --git a/app/views/start_form/completed.html.erb b/app/views/start_form/completed.html.erb index bb576a831..c432e273d 100644 --- a/app/views/start_form/completed.html.erb +++ b/app/views/start_form/completed.html.erb @@ -1,4 +1,4 @@ -
+
@@ -32,5 +32,5 @@ <% end %>
-
+ <%= render 'shared/attribution', link_path: '/start', account: @submitter.account %> diff --git a/app/views/start_form/email_verification.html.erb b/app/views/start_form/email_verification.html.erb index b1a8410eb..383d8c9f6 100644 --- a/app/views/start_form/email_verification.html.erb +++ b/app/views/start_form/email_verification.html.erb @@ -2,7 +2,7 @@ <% I18n.with_locale(@template.account.locale) do %> <% content_for(:html_description, t('account_name_has_invited_you_to_fill_and_sign_documents_online_effortlessly_with_a_secure_fast_and_user_friendly_digital_document_signing_solution', account_name: @template.account.name)) %> <% end %> -
+
@@ -55,4 +55,4 @@ <%= button_to t(:re_send_email), start_form_email_2fa_send_index_path, params: { slug: @template.slug, resend: true, submitter: { name: params[:name] || params.dig(:submitter, :name), email: params[:email] || params.dig(:submitter, :email), phone: params[:phone] || params.dig(:submitter, :phone) } }.compact, method: :post, id: 'resend_code', class: 'hidden' %> <% end %>
-
+ diff --git a/app/views/start_form/error.html.erb b/app/views/start_form/error.html.erb index 3c9f56dd9..289abe7ac 100644 --- a/app/views/start_form/error.html.erb +++ b/app/views/start_form/error.html.erb @@ -2,7 +2,7 @@ <% I18n.with_locale(@template.account.locale) do %> <% content_for(:html_description, t('account_name_has_invited_you_to_fill_and_sign_documents_online_effortlessly_with_a_secure_fast_and_user_friendly_digital_document_signing_solution', account_name: @template.account.name)) %> <% end %> -
+
@@ -28,4 +28,4 @@ <%= link_to t('back'), @resubmit_submitter ? submit_form_path(@resubmit_submitter.slug) : start_form_path(@template.slug, @submitter.slice(:name, :email, :phone).compact_blank), class: 'base-button' %>
-
+ diff --git a/app/views/start_form/private.html.erb b/app/views/start_form/private.html.erb index d0f645800..d022342fd 100644 --- a/app/views/start_form/private.html.erb +++ b/app/views/start_form/private.html.erb @@ -2,7 +2,7 @@ <% I18n.with_locale(@template.account.locale) do %> <% content_for(:html_description, t('share_link_is_currently_disabled')) %> <% end %> -
+
<%= render 'start_form/banner' %>

@@ -27,5 +27,5 @@ <%= button_to button_title(title: t('enable_shared_link'), icon: svg_icon('lock_open', class: 'w-6 h-6')), template_share_link_path(@template), params: { template: { shared_link: true }, redir: start_form_path(slug: @template.slug) }, method: :post, class: 'white-button w-full' %> <% end %> -

+ <%= render 'shared/attribution', link_path: '/start', account: @template.account %> diff --git a/app/views/start_form/show.html.erb b/app/views/start_form/show.html.erb index 097ff38ce..dfe336914 100644 --- a/app/views/start_form/show.html.erb +++ b/app/views/start_form/show.html.erb @@ -2,7 +2,7 @@ <% I18n.with_locale(@template.account.locale) do %> <% content_for(:html_description, t('account_name_has_invited_you_to_fill_and_sign_documents_online_effortlessly_with_a_secure_fast_and_user_friendly_digital_document_signing_solution', account_name: @template.account.name)) %> <% end %> -
+
@@ -66,4 +66,4 @@ <%= render 'shared/attribution', link_path: '/start', account: @template.account %> <%= render 'start_form/policy', account: @template.account %>
-
+ diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index e749af450..0599fc36b 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -11,7 +11,7 @@ <% 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_completed_at = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID_COMPLETED_AT_KEY }&.value == true %> -
+
<% unless native_tab == 'recipients' %>
<% unless turbo_native_app? %> @@ -394,7 +394,7 @@ <% end %> -
+ <% unless request.headers['HTTP_X_TURBO_REQUEST_ID'] %> <%= render 'scripts/autosize_field' %> <% end %> diff --git a/app/views/submit_form/completed.html.erb b/app/views/submit_form/completed.html.erb index 7c7693814..2b5855903 100644 --- a/app/views/submit_form/completed.html.erb +++ b/app/views/submit_form/completed.html.erb @@ -1,5 +1,5 @@ <% completed_at = @submitter.completed_at || @submitter.submission.completed_at %> -
+
@@ -51,5 +51,5 @@ <% end %>
-
+ <%= render 'shared/attribution', link_path: '/start', account: @submitter.account %> diff --git a/app/views/submit_form/email_2fa.html.erb b/app/views/submit_form/email_2fa.html.erb index 6bb4a584b..878bad01a 100644 --- a/app/views/submit_form/email_2fa.html.erb +++ b/app/views/submit_form/email_2fa.html.erb @@ -3,7 +3,7 @@ <% I18n.with_locale(@submitter.account.locale) do %> <% content_for(:html_description, t('account_name_has_invited_you_to_fill_and_sign_documents_online_effortlessly_with_a_secure_fast_and_user_friendly_digital_document_signing_solution', account_name: @submitter.account.name)) %> <% end %> -
+
@@ -70,4 +70,4 @@
<%= t('please_contact_the_requester_to_specify_your_email_for_two_factor_authentication') %>
<% end %>
-
+ diff --git a/app/views/submit_form/show.html.erb b/app/views/submit_form/show.html.erb index b02a8a273..9e62abdbd 100644 --- a/app/views/submit_form/show.html.erb +++ b/app/views/submit_form/show.html.erb @@ -14,7 +14,7 @@ <% delegate_modal_id = nil %> <% banner_html = turbo_native_app? ? '' : local_assigns[:banner_html] %>
-
+
<%# flex block w-full sticky top-0 z-50 space-x-2 items-center bg-yellow-100 p-2 border-y border-yellow-200 transition-transform duration-300 %> @@ -172,7 +172,7 @@ <% end %> <% end %>
-
+