From d08179854b19b25ec158eca1af188db7dba19e3d Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 14:31:17 -0400 Subject: [PATCH] feat: add fast track quick send feature (v0.13.0) * feat: add fast track quick send feature (v0.13.0) * fix: add missing 'required' i18n key to all 7 locales * fix: add Quick Send button to empty-state template view --------- Co-authored-by: Bob Develop --- .../templates_quick_send_controller.rb | 38 +++++++++++ app/views/templates/show.html.erb | 10 ++- app/views/templates_quick_send/show.html.erb | 63 +++++++++++++++++++ config/locales/i18n.yml | 63 +++++++++++++++++++ config/routes.rb | 1 + 5 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 app/controllers/templates_quick_send_controller.rb create mode 100644 app/views/templates_quick_send/show.html.erb diff --git a/app/controllers/templates_quick_send_controller.rb b/app/controllers/templates_quick_send_controller.rb new file mode 100644 index 00000000..a51f6556 --- /dev/null +++ b/app/controllers/templates_quick_send_controller.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +class TemplatesQuickSendController < ApplicationController + load_and_authorize_resource :template + + before_action :authorize_create_submission, only: :create + + def show + @fields = @template.fields + @submitters = @template.submitters + end + + def create + submissions = + Submissions.create_from_emails(template: @template, + user: current_user, + source: :invite, + mark_as_sent: true, + emails: params[:email], + params: { 'send_completed_email' => true }) + + WebhookUrls.enqueue_events(submissions, 'submission.created') + + Submissions.send_signature_requests(submissions) + + SearchEntries.enqueue_reindex(submissions) + + redirect_to template_path(@template), notice: I18n.t('submission_has_been_sent') + rescue Submissions::CreateFromSubmitters::BaseError => e + redirect_to template_path(@template), alert: e.message + end + + private + + def authorize_create_submission + authorize!(:create, Submission) + end +end diff --git a/app/views/templates/show.html.erb b/app/views/templates/show.html.erb index 508b8a23..0bced2c7 100644 --- a/app/views/templates/show.html.erb +++ b/app/views/templates/show.html.erb @@ -18,6 +18,10 @@ <%= t('export') %> <% end %> <% if !@template.archived_at? && can?(:create, Submission) %> + <%= link_to template_quick_send_path(@template), id: 'quick_send_button', class: 'white-button !border', data: { turbo_frame: 'modal' } do %> + <%= svg_icon('send', class: 'w-6 h-6 stroke-2') %> + <%= t('quick_send') %> + <% end %> <%= link_to new_template_submission_path(@template), id: 'add_recipients_button', class: 'white-button !border', data: { turbo_frame: 'modal' } do %> <%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %> <%= t('add_recipients_html') %> @@ -89,7 +93,11 @@

<%= t('send_an_invitation_to_fill_and_complete_the_form') %>

<% if can?(:create, Submission) %> - <%= link_to new_template_submission_path(@template, with_link: true), id: 'send_to_recipients_button', class: 'base-button mt-6', data: { turbo_frame: 'modal' } do %> + <%= link_to template_quick_send_path(@template), id: 'quick_send_button', class: 'base-button mt-6', data: { turbo_frame: 'modal' } do %> + <%= svg_icon('send', class: 'w-6 h-6 stroke-2') %> + <%= t('quick_send') %> + <% end %> + <%= link_to new_template_submission_path(@template, with_link: true), id: 'send_to_recipients_button', class: 'white-button w-full', data: { turbo_frame: 'modal' } do %> <%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %> <%= t('send_to_recipients') %> <% end %> diff --git a/app/views/templates_quick_send/show.html.erb b/app/views/templates_quick_send/show.html.erb new file mode 100644 index 00000000..09d90df6 --- /dev/null +++ b/app/views/templates_quick_send/show.html.erb @@ -0,0 +1,63 @@ +<%= render 'shared/turbo_modal_large', title: t('quick_send') do %> +
+ <% submitter_fields = @fields.select { |f| f['submitter_uuid'] == @submitters.first['uuid'] } %> + <% auto_fillable = submitter_fields.all? { |f| f['default_value'].present? || !f['required'] || f['type'].in?(%w[signature initials stamp]) } %> + <% if auto_fillable %> +
+ <%= svg_icon('circle_check', class: 'w-5 h-5 stroke-current shrink-0') %> + <%= t('all_fields_have_defaults') %> +
+ <% else %> +
+ <%= svg_icon('alert_circle', class: 'w-5 h-5 stroke-current shrink-0') %> + <%= t('some_fields_require_manual_input') %> +
+ <% end %> + <% if submitter_fields.present? %> +
+ +
+ + + + + + + + + + <% submitter_fields.each do |field| %> + + + + + + <% end %> + +
<%= t('name') %><%= t('type') %><%= t('value') %>
<%= field['name'].presence || field['type'].humanize %><%= field['type'] %> + <% if field['default_value'].present? %> + <%= truncate(Array(field['default_value']).join(', '), length: 40) %> + <% elsif field['type'].in?(%w[signature initials stamp]) %> + <%= t('filled_by_recipient') %> + <% elsif !field['required'] %> + <%= t('optional') %> + <% else %> + <%= t('required') %> + <% end %> +
+
+
+ <% end %> + <%= form_for '', url: template_quick_send_path(@template), method: :post, html: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %> +
+ + +
+
+ <%= f.button button_title(title: t('send_now'), icon: svg_icon('send', class: 'w-5 h-5')), class: 'base-button' %> +
+ <% end %> +
+<% end %> diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml index d90b1958..199bdef6 100644 --- a/config/locales/i18n.yml +++ b/config/locales/i18n.yml @@ -493,6 +493,15 @@ en: &en there_are_no_submissions: There are no Submissions send_an_invitation_to_fill_and_complete_the_form: Send an invitation to fill and complete the form send_to_recipients: Send to Recipients + quick_send: Quick Send + send_now: Send Now + recipient_email: Recipient Email + all_fields_have_defaults: All fields have defaults or are auto-fillable. + some_fields_require_manual_input: Some required fields do not have default values. + auto_filled_fields: Auto-filled Fields + filled_by_recipient: Filled by recipient + submission_has_been_sent: Submission has been sent. + required: Required sign_it_yourself: Sign it Yourself api_and_embedding: API and Embedding template_id: Template ID @@ -1539,6 +1548,15 @@ es: &es there_are_no_submissions: No hay envíos send_an_invitation_to_fill_and_complete_the_form: Enviar una invitación para completar el formulario send_to_recipients: Enviar a los destinatarios + quick_send: Envío rápido + send_now: Enviar ahora + recipient_email: Correo del destinatario + all_fields_have_defaults: Todos los campos tienen valores predeterminados o se completan automáticamente. + some_fields_require_manual_input: Algunos campos obligatorios no tienen valores predeterminados. + auto_filled_fields: Campos autocompletados + filled_by_recipient: Completado por el destinatario + submission_has_been_sent: El envío ha sido realizado. + required: Obligatorio sign_it_yourself: Fírmalo tú mismo api_and_embedding: API e Integración template_id: ID de plantilla @@ -2582,6 +2600,15 @@ it: &it there_are_no_submissions: Non ci sono invii send_an_invitation_to_fill_and_complete_the_form: Invia un invito per compilare e completare il modulo send_to_recipients: Invia ai destinatari + quick_send: Invio rapido + send_now: Invia ora + recipient_email: Email del destinatario + all_fields_have_defaults: Tutti i campi hanno valori predefiniti o sono compilabili automaticamente. + some_fields_require_manual_input: Alcuni campi obbligatori non hanno valori predefiniti. + auto_filled_fields: Campi compilati automaticamente + filled_by_recipient: Compilato dal destinatario + submission_has_been_sent: L'invio è stato effettuato. + required: Obbligatorio sign_it_yourself: Firmalo tu stesso api_and_embedding: API e Incorporazione template_id: ID modello @@ -3629,6 +3656,15 @@ fr: &fr there_are_no_submissions: Il n’y a aucune soumission send_an_invitation_to_fill_and_complete_the_form: Envoyer une invitation pour remplir et terminer le formulaire send_to_recipients: Envoyer aux destinataires + quick_send: Envoi rapide + send_now: Envoyer maintenant + recipient_email: Email du destinataire + all_fields_have_defaults: Tous les champs ont des valeurs par défaut ou sont remplis automatiquement. + some_fields_require_manual_input: Certains champs obligatoires n'ont pas de valeurs par défaut. + auto_filled_fields: Champs remplis automatiquement + filled_by_recipient: Rempli par le destinataire + submission_has_been_sent: L'envoi a été effectué. + required: Obligatoire sign_it_yourself: Signer vous‑même api_and_embedding: API et Embedding template_id: ID du modèle @@ -4669,6 +4705,15 @@ pt: &pt there_are_no_submissions: Não há submissões send_an_invitation_to_fill_and_complete_the_form: Enviar um convite para preencher e concluir o formulário send_to_recipients: Enviar para destinatários + quick_send: Envio rápido + send_now: Enviar agora + recipient_email: Email do destinatário + all_fields_have_defaults: Todos os campos têm valores padrão ou são preenchidos automaticamente. + some_fields_require_manual_input: Alguns campos obrigatórios não têm valores padrão. + auto_filled_fields: Campos preenchidos automaticamente + filled_by_recipient: Preenchido pelo destinatário + submission_has_been_sent: O envio foi realizado. + required: Obrigatório sign_it_yourself: Assine você mesmo api_and_embedding: API e Incorporação template_id: ID do modelo @@ -5712,6 +5757,15 @@ de: &de there_are_no_submissions: Es gibt keine Einreichungen send_an_invitation_to_fill_and_complete_the_form: Einladung zum Ausfüllen und Abschließen des Formulars senden send_to_recipients: An Empfänger senden + quick_send: Schnellversand + send_now: Jetzt senden + recipient_email: Empfänger-E-Mail + all_fields_have_defaults: Alle Felder haben Standardwerte oder werden automatisch ausgefüllt. + some_fields_require_manual_input: Einige Pflichtfelder haben keine Standardwerte. + auto_filled_fields: Automatisch ausgefüllte Felder + filled_by_recipient: Vom Empfänger ausgefüllt + submission_has_been_sent: Die Übermittlung wurde gesendet. + required: Erforderlich sign_it_yourself: Selbst unterschreiben api_and_embedding: API und Einbettung template_id: Vorlagen-ID @@ -7160,6 +7214,15 @@ nl: &nl there_are_no_submissions: Er zijn geen inzendingen send_an_invitation_to_fill_and_complete_the_form: Stuur een uitnodiging om het formulier in te vullen en te voltooien send_to_recipients: Verzenden naar ontvangers + quick_send: Snel verzenden + send_now: Nu verzenden + recipient_email: E-mail van ontvanger + all_fields_have_defaults: Alle velden hebben standaardwaarden of worden automatisch ingevuld. + some_fields_require_manual_input: Sommige verplichte velden hebben geen standaardwaarden. + auto_filled_fields: Automatisch ingevulde velden + filled_by_recipient: Ingevuld door ontvanger + submission_has_been_sent: De inzending is verzonden. + required: Vereist sign_it_yourself: Zelf ondertekenen api_and_embedding: API en insluiten template_id: Sjabloon-ID diff --git a/config/routes.rb b/config/routes.rb index 60afd92b..a05955f6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -112,6 +112,7 @@ Rails.application.routes.draw do resources :recipients, only: %i[create], controller: 'templates_recipients' resources :prefillable_fields, only: %i[create], controller: 'templates_prefillable_fields' resources :submissions_export, only: %i[index new] + resource :quick_send, only: %i[show create], controller: 'templates_quick_send' end resources :preview_document_page, only: %i[show], path: '/preview/:signed_key' resource :blobs_proxy, only: %i[show], path: '/file/:signed_uuid/*filename',