mirror of
https://github.com/docusealco/docuseal
synced 2026-11-04 14:42:32 -05:00
add search
This commit is contained in:
1 parent
8259ebdb6c
commit
ae5f87f8fb
28 files changed
+323
-34
No files matched your search
@@ -173,7 +173,6 @@ module Api
|
|||||||
end
|
end
|
||||||
|
|
||||||
def filter_submissions(submissions, params)
|
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?
|
submissions = submissions.where(slug: params[:slug]) if params[:slug].present?
|
||||||
|
|
||||||
if params[:template_folder].present?
|
if params[:template_folder].present?
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,27 +1,33 @@
|
|||||||
import { target, targetable } from '@github/catalyst/lib/targetable'
|
export default class extends HTMLElement {
|
||||||
|
|
||||||
export default targetable(class extends HTMLElement {
|
|
||||||
static [target.static] = ['form']
|
|
||||||
|
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
const bridge = window.webkit?.messageHandlers?.native
|
document.addEventListener('native:search', this.onSearch)
|
||||||
|
|
||||||
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 })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback () {
|
disconnectedCallback () {
|
||||||
if (this.declared) {
|
document.removeEventListener('native:search', this.onSearch)
|
||||||
window.webkit?.messageHandlers?.native?.postMessage({ type: 'search', op: 'remove' })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
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')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,7 +66,7 @@ function mouseoverListener (event) {
|
|||||||
} else if (linkElement.dataset.turboFrame !== '_top') {
|
} else if (linkElement.dataset.turboFrame !== '_top') {
|
||||||
const turboFrame = linkElement.closest('turbo-frame')
|
const turboFrame = linkElement.closest('turbo-frame')
|
||||||
|
|
||||||
if (turboFrame) {
|
if (turboFrame && turboFrame.getAttribute('target') !== '_top') {
|
||||||
requestOptions.headers['Turbo-Frame'] = turboFrame.id
|
requestOptions.headers['Turbo-Frame'] = turboFrame.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<%= render 'search/row', href: folder_path(folder), icon: 'folder', title: folder.name, subtitle: folder.parent_folder&.name %>
|
||||||
@@ -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 %>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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] %>
|
||||||
@@ -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 %>
|
||||||
@@ -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)) %>
|
||||||
@@ -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 %>
|
||||||
@@ -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,5 +1,5 @@
|
|||||||
<% if pagy.next || pagy.page > 1 %>
|
<% 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') %>
|
<%= svg_icon('loader', class: 'w-6 h-6 animate-spin') %>
|
||||||
</infinite-scroll>
|
</infinite-scroll>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
</native-action>
|
</native-action>
|
||||||
<% end %>
|
<% end %>
|
||||||
<native-action data-placement="profile" data-icon="logout" data-native="sign_out" data-label="<%= t('sign_out') %>" data-destructive="true"></native-action>
|
<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 %>
|
<% 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="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>
|
<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>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<native-search class="contents">
|
<% 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? %>" data-target="native-search.form">
|
<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| %>
|
<% Submissions::Filter::ALLOWED_PARAMS.each do |key| %>
|
||||||
<% if params[key].present? %>
|
<% if params[key].present? %>
|
||||||
<input name="<%= key %>" value="<%= params[key] %>" class="hidden">
|
<input name="<%= key %>" value="<%= params[key] %>" class="hidden">
|
||||||
@@ -27,4 +27,4 @@
|
|||||||
</button>
|
</button>
|
||||||
</search-input>
|
</search-input>
|
||||||
</form>
|
</form>
|
||||||
</native-search>
|
<% end %>
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
<% content_for(:native_title, t('archived')) if turbo_native_app? %>
|
<% content_for(:native_title, t('archived')) if turbo_native_app? %>
|
||||||
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
|
<% 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? %>
|
<% unless turbo_native_app? %>
|
||||||
<div>
|
<div>
|
||||||
<%= link_to root_path, class: 'flex items-center mb-1 md:mb-0' do %>
|
<%= 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 %>
|
<% 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? %>
|
<% is_show_tabs = (@pagy.count.nil? || @pagy.count >= 5) || params[:status].present? || filter_params.present? %>
|
||||||
<% if Docuseal.demo? %><%= render 'shared/demo_alert' %><% end %>
|
<% 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? %>">
|
<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) %>
|
<% query_params = params.permit(:q, :scope, :archived).merge(filter_params) %>
|
||||||
<% filter_names = %w[status folder author completed_at created_at] %>
|
<% 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 %>
|
<% 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 = ordered_filters.reverse.each_with_index.to_h { |name, index| [name, index + 1] } %>
|
||||||
<% chip_order.default = ordered_filters.size + 1 %>
|
<% chip_order.default = ordered_filters.size + 1 %>
|
||||||
@@ -22,6 +22,28 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% chips_html = capture do %>
|
<% 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? %>
|
<% 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') %>">
|
<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 %>
|
<%= 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 } %>
|
<% advanced_filters = filter_params.then { |f| f[:status].in?(%w[pending completed]) ? f.except(:status) : f } %>
|
||||||
<div class="dropdown dropdown-end shrink-0">
|
<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' %>">
|
<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 %>
|
<%= render 'shared/turbo_modal', title: local_assigns[:title] do %>
|
||||||
<%= form_for '', url: path, method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %>
|
<%= 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 :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| %>
|
<% local_assigns[:default_params].each do |key, value| %>
|
||||||
<%= hidden_field_tag(key, value) if value.present? %>
|
<%= hidden_field_tag(key, value) if value.present? %>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -12,7 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% if params[:with_remove] %>
|
<% if params[:with_remove] %>
|
||||||
<div class="text-center w-full mt-4">
|
<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>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<% content_for(:native_title, @template_folder.name) if turbo_native_app? %>
|
<% 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?) %>
|
<% 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') %>">
|
<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>
|
<a href="<%= templates_archived_index_path %>" data-native-title="<%= t('archived') %>"><%= t('view_archived') %></a>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<% is_show_header = submissions_count != 0 || params[:q].present? || params[:status].present? || filter_params.present? %>
|
<% is_show_header = submissions_count != 0 || params[:q].present? || params[:status].present? || filter_params.present? %>
|
||||||
<%= render 'title', template: @template, with_export: is_show_header %>
|
<%= render 'title', template: @template, with_export: is_show_header %>
|
||||||
<% if turbo_native_app? %>
|
<% 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) %>
|
<% if !@template.archived_at? && can?(:create, Submission) %>
|
||||||
<native-action data-placement="footer" data-icon="send" data-label="<%= t('send_to_recipients') %>">
|
<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>
|
<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? %>
|
<% 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? %>
|
<% unless turbo_native_app? %>
|
||||||
<div>
|
<div>
|
||||||
<%= link_to root_path, class: 'flex items-center mb-1 md:mb-0' do %>
|
<%= 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? %>
|
<% content_for(:native_title, t('archived')) if turbo_native_app? %>
|
||||||
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
|
<% 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? %>
|
<% with_filters = @pagy.pages > 1 || params[:q].present? || filter_params.present? %>
|
||||||
<% unless turbo_native_app? %>
|
<% unless turbo_native_app? %>
|
||||||
<%= render 'templates/title', template: @template %>
|
<%= render 'templates/title', template: @template %>
|
||||||
|
|||||||
@@ -483,6 +483,8 @@ en: &en
|
|||||||
document_templates_html: <span class="hidden lg:inline">Document</span> Templates
|
document_templates_html: <span class="hidden lg:inline">Document</span> Templates
|
||||||
archived: Archived
|
archived: Archived
|
||||||
search: Search
|
search: Search
|
||||||
|
no_results: No Results
|
||||||
|
folders: Folders
|
||||||
submissions_not_found: Submissions not Found
|
submissions_not_found: Submissions not Found
|
||||||
create: Create
|
create: Create
|
||||||
view_archived: View Archived
|
view_archived: View Archived
|
||||||
@@ -1624,6 +1626,8 @@ es: &es
|
|||||||
document_templates_html: Plantillas <span class="hidden lg:inline">de documento</span>
|
document_templates_html: Plantillas <span class="hidden lg:inline">de documento</span>
|
||||||
archived: Archivado
|
archived: Archivado
|
||||||
search: Buscar
|
search: Buscar
|
||||||
|
no_results: Sin resultados
|
||||||
|
folders: Carpetas
|
||||||
submissions_not_found: Envíos no encontrados
|
submissions_not_found: Envíos no encontrados
|
||||||
create: Crear
|
create: Crear
|
||||||
view_archived: Ver Archivados
|
view_archived: Ver Archivados
|
||||||
@@ -2769,6 +2773,8 @@ it: &it
|
|||||||
document_templates_html: Modelli <span class="hidden lg:inline">di documento</span>
|
document_templates_html: Modelli <span class="hidden lg:inline">di documento</span>
|
||||||
archived: Archiviato
|
archived: Archiviato
|
||||||
search: Cerca
|
search: Cerca
|
||||||
|
no_results: Nessun risultato
|
||||||
|
folders: Cartelle
|
||||||
submissions_not_found: Invii non trovati
|
submissions_not_found: Invii non trovati
|
||||||
create: Crea
|
create: Crea
|
||||||
view_archived: Visualizza Archiviati
|
view_archived: Visualizza Archiviati
|
||||||
@@ -3900,6 +3906,8 @@ fr: &fr
|
|||||||
document_templates_html: Modèles <span class="hidden lg:inline">de documents</span>
|
document_templates_html: Modèles <span class="hidden lg:inline">de documents</span>
|
||||||
archived: Archivé
|
archived: Archivé
|
||||||
search: Rechercher
|
search: Rechercher
|
||||||
|
no_results: Aucun résultat
|
||||||
|
folders: Dossiers
|
||||||
submissions_not_found: Soumissions introuvables
|
submissions_not_found: Soumissions introuvables
|
||||||
create: Créer
|
create: Créer
|
||||||
view_archived: Voir les archivés
|
view_archived: Voir les archivés
|
||||||
@@ -5041,6 +5049,8 @@ pt: &pt
|
|||||||
document_templates_html: Modelos <span class="hidden lg:inline">de documento</span>
|
document_templates_html: Modelos <span class="hidden lg:inline">de documento</span>
|
||||||
archived: Arquivado
|
archived: Arquivado
|
||||||
search: Buscar
|
search: Buscar
|
||||||
|
no_results: Sem resultados
|
||||||
|
folders: Pastas
|
||||||
submissions_not_found: Submissões não encontradas
|
submissions_not_found: Submissões não encontradas
|
||||||
create: Criar
|
create: Criar
|
||||||
view_archived: Ver arquivados
|
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>
|
document_templates_html: <span class="lg:hidden">Vorlagen</span><span class="hidden lg:inline">Dokumentvorlagen</span>
|
||||||
archived: Archiviert
|
archived: Archiviert
|
||||||
search: Suchen
|
search: Suchen
|
||||||
|
no_results: Keine Ergebnisse
|
||||||
|
folders: Ordner
|
||||||
submissions_not_found: Einreichungen nicht gefunden
|
submissions_not_found: Einreichungen nicht gefunden
|
||||||
create: Erstellen
|
create: Erstellen
|
||||||
view_archived: Archivierte anzeigen
|
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>
|
document_templates_html: <span class="lg:hidden">Sjablonen</span><span class="hidden lg:inline">Documentsjablonen</span>
|
||||||
archived: Gearchiveerd
|
archived: Gearchiveerd
|
||||||
search: Zoeken
|
search: Zoeken
|
||||||
|
no_results: Geen resultaten
|
||||||
|
folders: Mappen
|
||||||
submissions_not_found: Geen inzendingen gevonden
|
submissions_not_found: Geen inzendingen gevonden
|
||||||
create: Aanmaken
|
create: Aanmaken
|
||||||
view_archived: Archief bekijken
|
view_archived: Archief bekijken
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ Rails.application.routes.draw do
|
|||||||
resources :encrypted_user_configs, only: %i[destroy]
|
resources :encrypted_user_configs, only: %i[destroy]
|
||||||
resources :timestamp_server, only: %i[create] unless Docuseal.multitenant?
|
resources :timestamp_server, only: %i[create] unless Docuseal.multitenant?
|
||||||
resources :dashboard, only: %i[index]
|
resources :dashboard, only: %i[index]
|
||||||
|
resources :search, only: %i[index]
|
||||||
resources :setup, only: %i[index create]
|
resources :setup, only: %i[index create]
|
||||||
resource :newsletter, only: %i[show update]
|
resource :newsletter, only: %i[show update]
|
||||||
resources :enquiries, only: %i[create]
|
resources :enquiries, only: %i[create]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ module Submissions
|
|||||||
ALLOWED_PARAMS = %w[
|
ALLOWED_PARAMS = %w[
|
||||||
author
|
author
|
||||||
status
|
status
|
||||||
|
template_id
|
||||||
folder
|
folder
|
||||||
completed_at_from
|
completed_at_from
|
||||||
completed_at_to
|
completed_at_to
|
||||||
@@ -27,6 +28,7 @@ module Submissions
|
|||||||
filters = normalize_filter_params(params, current_user)
|
filters = normalize_filter_params(params, current_user)
|
||||||
|
|
||||||
submissions = filter_by_author(submissions, filters, 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_folder(submissions, filters, current_user)
|
||||||
submissions = filter_by_status(submissions, filters)
|
submissions = filter_by_status(submissions, filters)
|
||||||
submissions = filter_by_created_at(submissions, filters)
|
submissions = filter_by_created_at(submissions, filters)
|
||||||
@@ -42,6 +44,12 @@ module Submissions
|
|||||||
submissions.where(created_by_user_id: user&.id || -1)
|
submissions.where(created_by_user_id: user&.id || -1)
|
||||||
end
|
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)
|
def filter_by_status(submissions, filters)
|
||||||
case filters[:status]
|
case filters[:status]
|
||||||
when 'pending'
|
when 'pending'
|
||||||
|
|||||||
Reference in new issue
Block a user