add search

This commit is contained in:
Pete Matsyburka committed 2026-09-23 10:59:54 +03:00
1 parent 8259ebdb6c
commit ae5f87f8fb
28 files changed
+323 -34

No files matched your search

@@ -173,7 +173,6 @@ module Api
end
def filter_submissions(submissions, params)
submissions = submissions.where(template_id: params[:template_id]) if params[:template_id].present?
submissions = submissions.where(slug: params[:slug]) if params[:slug].present?
if params[:template_folder].present?
+132
View File
@@ -0,0 +1,132 @@
# frozen_string_literal: true
class SearchController < ApplicationController
load_and_authorize_resource :template_folder, parent: false
load_and_authorize_resource :template, parent: false
load_and_authorize_resource :submission, parent: false
load_and_authorize_resource :template, instance_name: :filter_template, id_param: :template_id, parent: true
FOLDERS_LIMIT = 4
LIMIT = 12
def index
@query = params[:q].to_s.squish
return render_infinite_scroll(@template_folders, @templates, @submissions, @query) if turbo_infinite_scroll?
if @query.blank?
@template_folders = @templates = @submissions = []
elsif params[:scope] == 'folders'
@folders_pagy, @template_folders =
pagy(:countless, filter_folders(@template_folders, @templates, @query), limit: LIMIT)
@templates = @submissions = []
else
folders = filter_folders(@template_folders, @templates, @query)
@pagy, @template_folders, @templates, @submissions =
if params[:scope] == 'submissions'
load_submissions_page(folders, @templates, @submissions, @query)
else
load_templates_page(folders, @templates, @submissions, @query)
end
if @templates.blank? && @submissions.blank? && params[:template_id].blank?
@folders_pagy, @template_folders = pagy(:countless, folders, limit: LIMIT)
end
end
end
private
def load_submissions_page(folders, templates, submissions, query)
pagy, submissions = pagy(:countless, filter_submissions(submissions, query), limit: LIMIT)
return [pagy, [], [], submissions] if pagy.next || params[:template_id].present?
[pagy, folders.limit(FOLDERS_LIMIT).to_a, filter_templates(templates, query).limit(LIMIT).to_a, submissions]
end
def load_templates_page(folders, templates, submissions, query)
pagy, templates = pagy(:countless, filter_templates(templates, query), limit: LIMIT)
submissions = pagy.next ? [] : filter_submissions(submissions, query).limit(LIMIT).to_a
[pagy, folders.limit(FOLDERS_LIMIT).to_a, templates, submissions]
end
def render_infinite_scroll(folders, templates, submissions, query)
target, partial, collection =
case params[:scope]
when 'folders'
['search_folders', 'search/folder', filter_folders(folders, templates, query)]
when 'submissions'
['search_submissions', 'search/submission', filter_submissions(submissions, query)]
else
['search_templates', 'search/template', filter_templates(templates, query)]
end
pagy, records = pagy(:countless, collection, limit: LIMIT)
render turbo_stream: [
turbo_stream.append(target, partial:, collection: records),
turbo_stream.replace('infinite_scroll', partial: 'shared/infinite_scroll', locals: { pagy: })
]
end
def filter_folders(folders, templates, query)
return folders.none if params[:archived] == 'true'
folders = folders.where.not(id: current_account.default_template_folder.id)
folders = folders.where(parent_folder_id: filter_folder_ids(params[:folder])) if params[:folder].present?
folders = folders.where(author_id: filter_author_id(params[:author])) if params[:author].present?
folders = TemplateFolders.filter_active_folders(folders, templates)
folders = TemplateFolders.search(folders, query)
folders.preload(:parent_folder).order(:name)
end
def filter_templates(templates, query)
templates = params[:archived] == 'true' ? templates.where.not(archived_at: nil) : templates.active
templates = templates.select_for_list.preload(:author, :template_accesses, folder: :parent_folder)
templates = templates.where(folder_id: filter_folder_ids(params[:folder])) if params[:folder].present?
templates = templates.where(author_id: filter_author_id(params[:author])) if params[:author].present?
Templates.search(current_user, templates, query).order(id: :desc)
end
def filter_folder_ids(folder_name)
TemplateFolders.filter_by_full_name(current_account.template_folders, folder_name)
.preload(:subfolders)
.flat_map { |folder| [folder.id, *folder.subfolders.map(&:id)] }
end
def filter_author_id(email)
current_account.users.find_by(email:)&.id || -1
end
def filter_submissions(submissions, query)
submissions = submissions.left_joins(:template)
submissions =
if params[:archived] == 'true'
submissions.where.not(archived_at: nil).or(submissions.where.not(templates: { archived_at: nil }))
else
submissions.where(archived_at: nil).where(templates: { archived_at: nil })
end
submissions = Submissions.search(current_user, submissions, query, search_template: true)
submissions = Submissions::Filter.call(submissions, current_user, params)
submissions =
if params[:status] == 'completed' || params[:completed_at_from].present? || params[:completed_at_to].present?
submissions.order(completed_at: :desc)
else
submissions.order(id: :desc)
end
submissions.select_for_list.preload(:submitters, :template)
end
end
+28 -22
View File
@@ -1,27 +1,33 @@
import { target, targetable } from '@github/catalyst/lib/targetable'
export default targetable(class extends HTMLElement {
static [target.static] = ['form']
export default class extends HTMLElement {
connectedCallback () {
const bridge = window.webkit?.messageHandlers?.native
if (!bridge || !this.form) return
const url = new URL(this.form.action)
new FormData(this.form).forEach((value, key) => {
if (key !== 'q' && value) url.searchParams.set(key, value)
})
this.declared = true
bridge.postMessage({ type: 'search', op: 'add', url: url.pathname + url.search })
document.addEventListener('native:search', this.onSearch)
}
disconnectedCallback () {
if (this.declared) {
window.webkit?.messageHandlers?.native?.postMessage({ type: 'search', op: 'remove' })
}
document.removeEventListener('native:search', this.onSearch)
}
})
onSearch = (event) => {
const query = (event.detail?.q || '').trim()
if (query === (this.dataset.q || '')) return
this.dataset.q = query
const url = new URL(this.frame.src || this.dataset.src, window.location.href)
url.searchParams.delete('page')
if (query) {
url.searchParams.set('q', query)
} else {
url.searchParams.delete('q')
}
this.frame.src = url.toString()
}
get frame () {
return this.querySelector('turbo-frame')
}
}
+1 -1
View File
@@ -66,7 +66,7 @@ function mouseoverListener (event) {
} else if (linkElement.dataset.turboFrame !== '_top') {
const turboFrame = linkElement.closest('turbo-frame')
if (turboFrame) {
if (turboFrame && turboFrame.getAttribute('target') !== '_top') {
requestOptions.headers['Turbo-Frame'] = turboFrame.id
}
}
+1
View File
@@ -0,0 +1 @@
<%= render 'search/row', href: folder_path(folder), icon: 'folder', title: folder.name, subtitle: folder.parent_folder&.name %>
+9
View File
@@ -0,0 +1,9 @@
<% if folders.present? %>
<div class="mb-5">
<div class="px-4 mb-1 text-xs font-semibold uppercase tracking-wide"><%= t('folders') %></div>
<div id="search_folders" class="bg-base-200 rounded-2xl divide-y divide-base-300">
<%= render partial: 'search/folder', collection: folders %>
</div>
<%= render 'shared/infinite_scroll', pagy:, query_params: { 'scope' => 'folders' } if pagy %>
</div>
<% end %>
+28
View File
@@ -0,0 +1,28 @@
<% with_filters = params[:scope] == 'submissions' || params[:archived] == 'true' || Submissions::Filter::ALLOWED_PARAMS.any? { |key| params[key].present? } %>
<turbo-frame id="search_results" class="block">
<% if with_filters %>
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
<style>html, body { overflow: hidden; }</style>
<div class="flex items-center gap-2 w-full">
<%= render 'submissions_filters/applied_filters', filter_params:, with_status: true, with_archived: true, filter_template: @filter_template %>
<%= render 'submissions_filters/filter_button', filter_params: %>
</div>
<% end %>
<div class="<%= 'overflow-y-auto -mx-4 px-4 md:-mx-2 md:px-2' if with_filters %>" style="<%= 'height: calc(100vh - 40px); padding-top: 16px; padding-bottom: 140px; -webkit-mask-image: linear-gradient(to bottom, transparent, black 16px); mask-image: linear-gradient(to bottom, transparent, black 16px);' if with_filters %>">
<% if @query.present? %>
<% if @template_folders.blank? && @templates.blank? && @submissions.blank? %>
<div class="text-center mt-16 text-xl">
<%= t('no_results') %>
</div>
<% end %>
<% if params[:scope] == 'submissions' %>
<%= render 'search/submissions', submissions: @submissions, pagy: @pagy %>
<% end %>
<%= render 'search/folders', folders: @template_folders, pagy: @folders_pagy %>
<%= render 'search/templates', templates: @templates, pagy: (@pagy unless params[:scope] == 'submissions') %>
<% unless params[:scope] == 'submissions' %>
<%= render 'search/submissions', submissions: @submissions, pagy: nil %>
<% end %>
<% end %>
</div>
</turbo-frame>
+18
View File
@@ -0,0 +1,18 @@
<% subtitle = local_assigns[:subtitle].presence %>
<% badge = local_assigns[:badge].presence %>
<% date = local_assigns[:date] %>
<a href="<%= href %>" data-turbo-frame="_top" class="flex items-center gap-3 pl-4 py-3 min-h-14" style="padding-right: 20px;" data-native-title="<%= title %>" data-native-actions="<%= local_assigns[:native_actions] %>">
<%= svg_icon(icon, class: 'w-6 h-6 shrink-0') %>
<div class="min-w-0 flex-1 items-center" style="display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 8px;">
<div class="truncate" style="grid-column: <%= badge || !subtitle ? '1' : '1 / span 2' %>; grid-row: <%= subtitle ? '1' : '1 / span 2' %>;"><%= title %></div>
<% if subtitle %>
<div class="text-xs text-base-content/60 truncate" style="grid-column: 1; grid-row: 2;"><%= subtitle %></div>
<% end %>
<% if badge %>
<span class="badge badge-sm <%= badge_class %> bg-opacity-50 uppercase font-semibold justify-self-end" style="grid-column: 2; grid-row: 1; font-size: 10px;"><%= badge %></span>
<% end %>
<% if date %>
<span class="text-xs text-base-content/60 justify-self-end" style="grid-column: 2; grid-row: <%= badge || subtitle ? '2' : '1 / span 2' %>;"><%= l(date.in_time_zone(current_account.timezone).to_date, format: :short, locale: current_account.locale) %></span>
<% end %>
</div>
</a>
+4
View File
@@ -0,0 +1,4 @@
<% status = submission.completed_at? ? 'completed' : (submission.expired? ? 'expired' : 'pending') %>
<% name = submission.name.presence || submission.template&.name %>
<% submitters = submission.submitters.filter_map { |s| s.name.presence || s.email.presence || s.phone.presence }.join(', ') %>
<%= render 'search/row', href: submission_path(submission), icon: 'file_text', title: submitters, subtitle: (name if params[:template_id].blank?), date: (params[:status] == 'completed' && submission.completed_at) || submission.created_at, badge: t(status), badge_class: { 'completed' => 'badge-success', 'expired' => 'badge-error', 'pending' => 'badge-info' }[status] %>
+9
View File
@@ -0,0 +1,9 @@
<% if submissions.present? %>
<div class="mb-5">
<div class="px-4 mb-1 text-xs font-semibold uppercase tracking-wide"><%= t('submissions') %></div>
<div id="search_submissions" class="bg-base-200 rounded-2xl divide-y divide-base-300">
<%= render partial: 'search/submission', collection: submissions %>
</div>
<%= render 'shared/infinite_scroll', pagy: pagy if pagy %>
</div>
<% end %>
+2
View File
@@ -0,0 +1,2 @@
<% author = template.author.full_name.presence || template.author.email.to_s.sub(/\+\w+@/, '@') %>
<%= render 'search/row', href: template_path(template), icon: 'layout_grid', title: template.name, subtitle: template.folder.default? || params[:folder].present? ? author : template.folder.full_name, date: template.created_at, native_actions: ('pencil,menu' if turbo_native_app? && !template.archived_at? && can?(:update, template)) %>
+9
View File
@@ -0,0 +1,9 @@
<% if templates.present? %>
<div class="mb-5">
<div class="px-4 mb-1 text-xs font-semibold uppercase tracking-wide"><%= t('templates') %></div>
<div id="search_templates" class="bg-base-200 rounded-2xl divide-y divide-base-300">
<%= render partial: 'search/template', collection: templates %>
</div>
<%= render 'shared/infinite_scroll', pagy: pagy if pagy %>
</div>
<% end %>
+10
View File
@@ -0,0 +1,10 @@
<% content_for(:native_title, t('search')) if turbo_native_app? %>
<% unless turbo_native_app? %>
<div class="flex justify-between items-center mb-4">
<h1 class="text-2xl md:text-3xl sm:text-4xl font-bold"><%= t('search') %></h1>
<%= render 'shared/search_input', placeholder: t('search') %>
</div>
<% end %>
<native-search class="block" data-src="<%= url_for(params: request.query_parameters.except('q', 'page')) %>" data-q="<%= @query %>">
<%= render 'search/results' %>
</native-search>
+1 -1
View File
@@ -1,5 +1,5 @@
<% if pagy.next || pagy.page > 1 %>
<infinite-scroll id="infinite_scroll" class="col-span-full flex justify-center py-2" data-src="<%= url_for(params: request.query_parameters.merge('page' => pagy.next)) if pagy.next %>">
<infinite-scroll id="infinite_scroll" class="col-span-full flex justify-center py-2" data-src="<%= url_for(params: request.query_parameters.merge(local_assigns[:query_params].to_h).merge('page' => pagy.next)) if pagy.next %>">
<%= svg_icon('loader', class: 'w-6 h-6 animate-spin') %>
</infinite-scroll>
<% end %>
+1 -1
View File
@@ -11,7 +11,7 @@
</native-action>
<% end %>
<native-action data-placement="profile" data-icon="logout" data-native="sign_out" data-label="<%= t('sign_out') %>" data-destructive="true"></native-action>
<% if can?(:create, ::Template) && controller_name.in?(%w[templates_dashboard submissions_dashboard template_folders]) %>
<% if can?(:create, ::Template) && controller_name.in?(%w[templates_dashboard submissions_dashboard template_folders templates_archived submissions_archived]) %>
<% folder_name = @template_folder&.full_name %>
<native-action data-placement="create" data-icon="upload" data-native="upload" data-label="<%= t('upload') %>" data-url="<%= templates_upload_path(folder_name: folder_name) %>" data-accept="image/*, application/pdf, application/zip, application/json<%= ", #{Templates::CreateAttachments::DOCUMENT_EXTENSIONS.join(', ')}" if Docuseal.advanced_formats? %>"></native-action>
<native-action data-placement="create" data-icon="scan" data-native="scan" data-label="<%= t('scan') %>" data-url="<%= templates_upload_path(folder_name: folder_name) %>"></native-action>
+3 -3
View File
@@ -1,5 +1,5 @@
<native-search class="contents">
<form action="<%= url_for %>" method="get" class="items-center flex max-md:focus-within:flex-1 <%= 'max-md:flex-1' if params[:q].present? %>" data-target="native-search.form">
<% unless turbo_native_app? %>
<form action="<%= url_for %>" method="get" class="items-center flex max-md:focus-within:flex-1 <%= 'max-md:flex-1' if params[:q].present? %>">
<% Submissions::Filter::ALLOWED_PARAMS.each do |key| %>
<% if params[key].present? %>
<input name="<%= key %>" value="<%= params[key] %>" class="hidden">
@@ -27,4 +27,4 @@
</button>
</search-input>
</form>
</native-search>
<% end %>
@@ -1,5 +1,8 @@
<% content_for(:native_title, t('archived')) if turbo_native_app? %>
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
<% if turbo_native_app? %>
<native-action data-placement="search" data-native="search" data-label="<%= t('search') %>" data-url="<%= search_index_path(filter_params.to_h.merge('scope' => 'submissions', 'archived' => 'true')) %>"></native-action>
<% end %>
<% unless turbo_native_app? %>
<div>
<%= link_to root_path, class: 'flex items-center mb-1 md:mb-0' do %>
@@ -1,4 +1,7 @@
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
<% if turbo_native_app? %>
<native-action data-placement="search" data-native="search" data-label="<%= t('search') %>" data-url="<%= search_index_path(filter_params.to_h.merge('scope' => 'submissions')) %>"></native-action>
<% end %>
<% is_show_tabs = (@pagy.count.nil? || @pagy.count >= 5) || params[:status].present? || filter_params.present? %>
<% if Docuseal.demo? %><%= render 'shared/demo_alert' %><% end %>
<div class="group/header flex justify-between items-center w-full <%= 'mb-4' unless turbo_native_app? %>">
@@ -1,5 +1,5 @@
<% query_params = params.permit(:q).merge(filter_params) %>
<% filter_names = %w[status folder author completed_at created_at] %>
<% query_params = params.permit(:q, :scope, :archived).merge(filter_params) %>
<% filter_names = %w[status archived template folder author completed_at created_at] %>
<% ordered_filters = request.query_parameters.keys.filter_map { |key| filter_names.find { |name| key.start_with?(name) } }.uniq %>
<% chip_order = ordered_filters.reverse.each_with_index.to_h { |name, index| [name, index + 1] } %>
<% chip_order.default = ordered_filters.size + 1 %>
@@ -22,6 +22,28 @@
<% end %>
<% end %>
<% chips_html = capture do %>
<% if local_assigns[:with_archived] && params[:archived] == 'true' %>
<div class="order-<%= chip_order['archived'] %> md:order-none flex md:flex h-10 px-2 py-1 text-base md:text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl shrink-0 max-w-[60vw] md:w-36 border-neutral-700">
<span class="flex items-center space-x-1 flex-1 min-w-0 pr-1">
<%= svg_icon('archive', class: 'w-5 h-5 shrink-0') %>
<span class="font-normal truncate"><%= t('archived') %></span>
</span>
<%= link_to url_for(params: request.query_parameters.except('archived')), class: 'rounded-lg ml-1 shrink-0 hover:bg-base-content hover:text-white' do %>
<%= svg_icon('x', class: 'w-5 h-5') %>
<% end %>
</div>
<% end %>
<% if params[:template_id].present? %>
<div class="order-<%= chip_order['template'] %> md:order-none flex md:flex h-10 px-2 py-1 text-base md:text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl shrink-0 max-w-[60vw] md:w-36 border-neutral-700">
<span class="flex items-center space-x-1 flex-1 min-w-0 pr-1">
<%= svg_icon('layout_grid', class: 'w-5 h-5 shrink-0') %>
<span class="font-normal truncate"><%= local_assigns[:filter_template]&.name || 'NA' %></span>
</span>
<%= link_to url_for(params: request.query_parameters.except('template_id')), class: 'rounded-lg ml-1 shrink-0 hover:bg-base-content hover:text-white' do %>
<%= svg_icon('x', class: 'w-5 h-5') %>
<% end %>
</div>
<% end %>
<% if params[:folder].present? %>
<div class="order-<%= chip_order['folder'] %> md:order-none md:tooltip tooltip-no-touch tooltip-bottom flex md:flex h-10 px-2 py-1 text-base md:text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl shrink-0 max-w-[60vw] md:w-36 border-neutral-700" data-tip="<%= t('folder') %>">
<%= link_to submissions_filter_path('folder', query_params.merge(path: url_for, with_remove: true)), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1 flex-1 min-w-0 pr-1' do %>
@@ -1,4 +1,4 @@
<% query_params = params.permit(:q).merge(filter_params) %>
<% query_params = params.permit(:q, :scope, :archived).merge(filter_params) %>
<% advanced_filters = filter_params.then { |f| f[:status].in?(%w[pending completed]) ? f.except(:status) : f } %>
<div class="dropdown dropdown-end shrink-0">
<label tabindex="0" class="cursor-pointer flex h-10 py-1 text-lg items-center border text-center text-neutral rounded-xl hover:border-neutral-700 <%= advanced_filters.present? ? 'w-10 md:w-auto px-0 md:px-3 space-x-0 md:space-x-1 justify-center md:justify-between border-neutral-700 md:border-neutral-300' : 'px-3 space-x-1 justify-between border-neutral-300' %>">
@@ -3,6 +3,8 @@
<%= render 'shared/turbo_modal', title: local_assigns[:title] do %>
<%= form_for '', url: path, method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %>
<%= hidden_field_tag :q, params[:q] if params[:q].present? %>
<%= hidden_field_tag :scope, params[:scope] if params[:scope].present? %>
<%= hidden_field_tag :archived, params[:archived] if params[:archived].present? %>
<% local_assigns[:default_params].each do |key, value| %>
<%= hidden_field_tag(key, value) if value.present? %>
<% end %>
@@ -12,7 +14,7 @@
</div>
<% if params[:with_remove] %>
<div class="text-center w-full mt-4">
<%= link_to t('remove_filter'), "#{path}?#{request.query_parameters.slice('q').merge(local_assigns[:default_params]).to_query}", class: 'link', data: { turbo_frame: :_top } %>
<%= link_to t('remove_filter'), "#{path}?#{request.query_parameters.slice('q', 'scope', 'archived').merge(local_assigns[:default_params]).to_query}", class: 'link', data: { turbo_frame: :_top } %>
</div>
<% end %>
<% end %>
+3
View File
@@ -1,4 +1,7 @@
<% content_for(:native_title, @template_folder.name) if turbo_native_app? %>
<% if turbo_native_app? %>
<native-action data-placement="search" data-native="search" data-label="<%= t('search') %>" data-url="<%= search_index_path(folder: @template_folder.full_name) %>"></native-action>
<% end %>
<% if turbo_native_app? && (can?(:manage, :countless) || current_account.templates.where.not(archived_at: nil).exists?) %>
<native-action data-placement="menu" data-icon="archive" data-label="<%= t('archived') %>">
<a href="<%= templates_archived_index_path %>" data-native-title="<%= t('archived') %>"><%= t('view_archived') %></a>
+1 -1
View File
@@ -5,7 +5,7 @@
<% is_show_header = submissions_count != 0 || params[:q].present? || params[:status].present? || filter_params.present? %>
<%= render 'title', template: @template, with_export: is_show_header %>
<% if turbo_native_app? %>
<%= render 'shared/search_input' %>
<native-action data-placement="search" data-native="search" data-label="<%= t('search') %>" data-url="<%= search_index_path(filter_params.to_h.merge({ 'scope' => 'submissions', 'template_id' => @template.id, 'archived' => ('true' if @template.archived_at?) }.compact)) %>"></native-action>
<% if !@template.archived_at? && can?(:create, Submission) %>
<native-action data-placement="footer" data-icon="send" data-label="<%= t('send_to_recipients') %>">
<a href="<%= new_template_submission_path(@template) %>" data-turbo-frame="modal"></a>
@@ -1,4 +1,7 @@
<% content_for(:native_title, t('archived')) if turbo_native_app? %>
<% if turbo_native_app? %>
<native-action data-placement="search" data-native="search" data-label="<%= t('search') %>" data-url="<%= search_index_path(archived: true) %>"></native-action>
<% end %>
<% unless turbo_native_app? %>
<div>
<%= link_to root_path, class: 'flex items-center mb-1 md:mb-0' do %>
@@ -1,5 +1,8 @@
<% content_for(:native_title, t('archived')) if turbo_native_app? %>
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
<% if turbo_native_app? %>
<native-action data-placement="search" data-native="search" data-label="<%= t('search') %>" data-url="<%= search_index_path(filter_params.to_h.merge('scope' => 'submissions', 'archived' => 'true', 'template_id' => @template.id)) %>"></native-action>
<% end %>
<% with_filters = @pagy.pages > 1 || params[:q].present? || filter_params.present? %>
<% unless turbo_native_app? %>
<%= render 'templates/title', template: @template %>
+14
View File
@@ -483,6 +483,8 @@ en: &en
document_templates_html: <span class="hidden lg:inline">Document</span> Templates
archived: Archived
search: Search
no_results: No Results
folders: Folders
submissions_not_found: Submissions not Found
create: Create
view_archived: View Archived
@@ -1624,6 +1626,8 @@ es: &es
document_templates_html: Plantillas <span class="hidden lg:inline">de documento</span>
archived: Archivado
search: Buscar
no_results: Sin resultados
folders: Carpetas
submissions_not_found: Envíos no encontrados
create: Crear
view_archived: Ver Archivados
@@ -2769,6 +2773,8 @@ it: &it
document_templates_html: Modelli <span class="hidden lg:inline">di documento</span>
archived: Archiviato
search: Cerca
no_results: Nessun risultato
folders: Cartelle
submissions_not_found: Invii non trovati
create: Crea
view_archived: Visualizza Archiviati
@@ -3900,6 +3906,8 @@ fr: &fr
document_templates_html: Modèles <span class="hidden lg:inline">de documents</span>
archived: Archivé
search: Rechercher
no_results: Aucun résultat
folders: Dossiers
submissions_not_found: Soumissions introuvables
create: Créer
view_archived: Voir les archivés
@@ -5041,6 +5049,8 @@ pt: &pt
document_templates_html: Modelos <span class="hidden lg:inline">de documento</span>
archived: Arquivado
search: Buscar
no_results: Sem resultados
folders: Pastas
submissions_not_found: Submissões não encontradas
create: Criar
view_archived: Ver arquivados
@@ -6185,6 +6195,8 @@ de: &de
document_templates_html: <span class="lg:hidden">Vorlagen</span><span class="hidden lg:inline">Dokumentvorlagen</span>
archived: Archiviert
search: Suchen
no_results: Keine Ergebnisse
folders: Ordner
submissions_not_found: Einreichungen nicht gefunden
create: Erstellen
view_archived: Archivierte anzeigen
@@ -7857,6 +7869,8 @@ nl: &nl
document_templates_html: <span class="lg:hidden">Sjablonen</span><span class="hidden lg:inline">Documentsjablonen</span>
archived: Gearchiveerd
search: Zoeken
no_results: Geen resultaten
folders: Mappen
submissions_not_found: Geen inzendingen gevonden
create: Aanmaken
view_archived: Archief bekijken
+1
View File
@@ -58,6 +58,7 @@ Rails.application.routes.draw do
resources :encrypted_user_configs, only: %i[destroy]
resources :timestamp_server, only: %i[create] unless Docuseal.multitenant?
resources :dashboard, only: %i[index]
resources :search, only: %i[index]
resources :setup, only: %i[index create]
resource :newsletter, only: %i[show update]
resources :enquiries, only: %i[create]
+8
View File
@@ -5,6 +5,7 @@ module Submissions
ALLOWED_PARAMS = %w[
author
status
template_id
folder
completed_at_from
completed_at_to
@@ -27,6 +28,7 @@ module Submissions
filters = normalize_filter_params(params, current_user)
submissions = filter_by_author(submissions, filters, current_user)
submissions = filter_by_template(submissions, filters)
submissions = filter_by_folder(submissions, filters, current_user)
submissions = filter_by_status(submissions, filters)
submissions = filter_by_created_at(submissions, filters)
@@ -42,6 +44,12 @@ module Submissions
submissions.where(created_by_user_id: user&.id || -1)
end
def filter_by_template(submissions, filters)
return submissions if filters[:template_id].blank?
submissions.where(template_id: filters[:template_id])
end
def filter_by_status(submissions, filters)
case filters[:status]
when 'pending'