diff --git a/app/controllers/templates_dashboard_controller.rb b/app/controllers/templates_dashboard_controller.rb index 4497038e..470833be 100644 --- a/app/controllers/templates_dashboard_controller.rb +++ b/app/controllers/templates_dashboard_controller.rb @@ -11,33 +11,32 @@ class TemplatesDashboardController < ApplicationController helper_method :selected_order def index + @default_folder = current_account.default_template_folder + @template_folders = TemplateFolders.filter_active_folders(@template_folders.where(parent_folder_id: nil), @templates) + @template_folders = @template_folders.where.not(id: @default_folder.id) if params[:q].blank? + @template_folders = TemplateFolders.search(@template_folders, params[:q]) @template_folders = TemplateFolders.sort(@template_folders, current_user, selected_order) - @pagy, @template_folders = pagy( - @template_folders, - limit: FOLDERS_PER_PAGE, - page: @template_folders.count > SHOW_TEMPLATES_FOLDERS_THRESHOLD ? params[:page] : 1 - ) + @shared_templates = Templates.shared(current_user).active + + @pagy, @template_folders, @show_default_folder, @show_shared_folder, @show_shared_inline = + load_folders(@template_folders, @templates, @shared_templates) if @pagy.count > SHOW_TEMPLATES_FOLDERS_THRESHOLD @templates = @templates.none else - @template_folders = @template_folders.reject { |e| e.name == TemplateFolder::DEFAULT_NAME } - @templates = filter_templates(@templates).preload(:author, :template_accesses) - @templates = Templates::Order.call(@templates, current_user, selected_order) - - limit = - if @template_folders.size < 4 - TEMPLATES_PER_PAGE - else - (@template_folders.size < 7 ? 9 : 6) - end + if @show_shared_inline + @templates = @shared_templates.preload(:template_sharings) + else + @templates = @templates.active + @templates = @templates.where(folder_id: @default_folder.id) if params[:q].blank? + end - @pagy, @templates = pagy_auto(@templates, limit:) + @pagy, @templates = load_templates(@templates, @pagy.count) load_related_submissions if params[:q].present? && @templates.blank? end @@ -45,28 +44,60 @@ class TemplatesDashboardController < ApplicationController private - def filter_templates(templates) - rel = templates.active + def load_templates(templates, folders_count) + templates = templates.preload(:author, :template_accesses) + templates = Templates.search(current_user, templates, params[:q]) + templates = Templates::Order.call(templates, current_user, selected_order) - if params[:q].blank? - if Docuseal.multitenant? ? current_account.testing? : current_account.linked_account_account - shared_account_ids = [current_user.account_id] - shared_account_ids << TemplateSharing::ALL_ID if !Docuseal.multitenant? && !current_account.testing? - - shared_template_ids = TemplateSharing.where(account_id: shared_account_ids).select(:template_id) - - rel = Template.where( - Template.arel_table[:id].in( - rel.where(folder_id: current_account.default_template_folder.id).select(:id).arel - .union(:all, shared_template_ids.arel) - ) - ) + limit = + if folders_count < 4 + TEMPLATES_PER_PAGE else - rel = rel.where(folder_id: current_account.default_template_folder.id) + (folders_count < 7 ? 9 : 6) end + + pagy_auto(templates, limit:) + end + + def load_folders(template_folders, templates, shared_templates) + if params[:q].present? + pagy(template_folders, limit: FOLDERS_PER_PAGE, + page: template_folders.count > SHOW_TEMPLATES_FOLDERS_THRESHOLD ? params[:page] : 1) + else + load_folders_with_pinned(template_folders, templates, shared_templates) end + end + + def load_folders_with_pinned(template_folders, templates, shared_templates) + folders_count = template_folders.count + + shared_exists = shared_templates.exists? + default_has_templates = templates.active.exists?(folder_id: current_account.default_template_folder.id) + + show_inline_folders = + folders_count + (shared_exists && default_has_templates ? 1 : 0) <= SHOW_TEMPLATES_FOLDERS_THRESHOLD + + show_shared_inline = shared_exists && !default_has_templates && show_inline_folders + + show_shared_in_grid = shared_exists && !show_shared_inline + show_default_in_grid = !show_inline_folders && default_has_templates + + pinned_count = (show_default_in_grid ? 1 : 0) + (show_shared_in_grid ? 1 : 0) + + pagy = Pagy::Offset.new(count: folders_count + pinned_count, + page: show_inline_folders ? 1 : [params[:page].to_s.to_i, 1].max, + limit: FOLDERS_PER_PAGE, + raise_range_error: true) + + show_default_folder = show_default_in_grid && pagy.page == 1 + show_shared_folder = show_shared_in_grid && pagy.page == 1 + + folder_offset = pagy.page == 1 ? 0 : pagy.offset - pinned_count + folder_limit = pagy.page == 1 ? FOLDERS_PER_PAGE - pinned_count : FOLDERS_PER_PAGE + + template_folders = template_folders.offset(folder_offset).limit(folder_limit) - Templates.search(current_user, rel, params[:q]) + [pagy, template_folders, show_default_folder, show_shared_folder, show_shared_inline] end def selected_order diff --git a/app/controllers/templates_shared_controller.rb b/app/controllers/templates_shared_controller.rb new file mode 100644 index 00000000..ea6193aa --- /dev/null +++ b/app/controllers/templates_shared_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class TemplatesSharedController < ApplicationController + def index + authorize!(:read, Template) + + @templates = Templates.shared(current_user) + .active + .preload(:author, :template_accesses, :template_sharings) + .order(id: :desc) + + @templates = Templates.search(current_user, @templates, params[:q]) + + @pagy, @templates = pagy_auto(@templates, limit: 12) + end +end diff --git a/app/views/icons/_folder_star.html.erb b/app/views/icons/_folder_star.html.erb new file mode 100644 index 00000000..a81a41e4 --- /dev/null +++ b/app/views/icons/_folder_star.html.erb @@ -0,0 +1,5 @@ + + + + + diff --git a/app/views/icons/_folder_up.html.erb b/app/views/icons/_folder_up.html.erb new file mode 100644 index 00000000..87285695 --- /dev/null +++ b/app/views/icons/_folder_up.html.erb @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/views/template_folders/_folder.html.erb b/app/views/template_folders/_folder.html.erb index 8413e045..b7571a1f 100644 --- a/app/views/template_folders/_folder.html.erb +++ b/app/views/template_folders/_folder.html.erb @@ -1,11 +1,12 @@ <% is_long = folder.name.size > 32 %> +<% icon = folder.default? ? 'folder_star' : 'folder' %> <% if !is_long %> - <%= svg_icon('folder', class: 'w-6 h-6') %> + <%= svg_icon(icon, class: 'w-6 h-6') %> <% end %>
<% if is_long %> - <%= svg_icon('folder', class: 'w-6 h-6 inline') %> + <%= svg_icon(icon, class: 'w-6 h-6 inline') %> <% end %> <%= folder.name %>
diff --git a/app/views/template_folders/_shared_folder.html.erb b/app/views/template_folders/_shared_folder.html.erb new file mode 100644 index 00000000..f76ea598 --- /dev/null +++ b/app/views/template_folders/_shared_folder.html.erb @@ -0,0 +1,6 @@ +
+ <%= svg_icon('folder_up', class: 'w-6 h-6') %> +
+ <%= t('shared') %> +
+
diff --git a/app/views/templates_dashboard/index.html.erb b/app/views/templates_dashboard/index.html.erb index 75f8f371..b11c3c7c 100644 --- a/app/views/templates_dashboard/index.html.erb +++ b/app/views/templates_dashboard/index.html.erb @@ -49,8 +49,14 @@ <%= render 'shared/templates_order_select', with_recently_used: @pagy.count.present? && @pagy.count < 10_000 && !can?(:manage, :countless), selected_order: %> <% end %> <% end %> - <% if @template_folders.present? %> + <% if @template_folders.present? || @show_default_folder || @show_shared_folder %>
+ <% if @show_default_folder %> + <%= render 'template_folders/folder', folder: @default_folder %> + <% end %> + <% if @show_shared_folder %> + <%= render 'template_folders/shared_folder' %> + <% end %> <%= render partial: 'template_folders/folder', collection: @template_folders, as: :folder %>
<% end %> diff --git a/app/views/templates_shared/index.html.erb b/app/views/templates_shared/index.html.erb new file mode 100644 index 00000000..c7bf456d --- /dev/null +++ b/app/views/templates_shared/index.html.erb @@ -0,0 +1,29 @@ +
+ <%= link_to root_path, class: 'flex items-center' do %> + <%= svg_icon('chevron_left', class: 'w-5 h-5') %> + <%= t('home') %> + <% end %> +
+
+

+ <%= svg_icon('folder', class: 'w-9 h-9 flex-shrink-0') %> + <%= t('shared') %> +

+
+ <% if params[:q].present? || @pagy.pages > 1 %> + <%= render 'shared/search_input' %> + <% end %> +
+
+<% if @pagy.count.nil? || @pagy.count > 0 %> +
+ <%= render partial: 'templates/template', collection: @templates %> +
+<% elsif params[:q].present? %> +
+
+ <%= t('templates_not_found') %> +
+
+<% end %> +<%= render 'shared/pagination', pagy: @pagy, items_name: 'templates' %> diff --git a/config/routes.rb b/config/routes.rb index 040a5759..e1100e04 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -91,6 +91,7 @@ Rails.application.routes.draw do resource :templates_upload, only: %i[show], path: 'new' end resources :templates_archived, only: %i[index], path: 'templates/archived' + resources :templates_shared, only: %i[index], path: 'templates/shared' resources :folders, only: %i[show edit update destroy], controller: 'template_folders' resources :template_sharings_testing, only: %i[create] resources :templates, only: %i[index], controller: 'templates_dashboard' diff --git a/lib/abilities/template_conditions.rb b/lib/abilities/template_conditions.rb index dede24ce..19c6cd82 100644 --- a/lib/abilities/template_conditions.rb +++ b/lib/abilities/template_conditions.rb @@ -4,16 +4,8 @@ module Abilities module TemplateConditions module_function - def collection(user, ability: nil) - templates = Template.where(account_id: user.account_id) - - return templates unless user.account.testing? - - shared_ids = - TemplateSharing.where({ ability:, account_id: [user.account_id, TemplateSharing::ALL_ID] }.compact) - .select(:template_id) - - Template.where(Template.arel_table[:id].in(templates.select(:id).arel.union(:all, shared_ids.arel))) + def collection(user) + Template.where(account_id: user.account_id) end def entity(template, user:, ability: nil) diff --git a/lib/templates.rb b/lib/templates.rb index 620edf3a..38cda986 100644 --- a/lib/templates.rb +++ b/lib/templates.rb @@ -47,6 +47,21 @@ module Templates nil end + def shared(current_user) + account = current_user.account + + return Template.none if Docuseal.multitenant? ? !account.testing? : !account.linked_account_account + + shared_account_ids = [current_user.account_id] + shared_account_ids << TemplateSharing::ALL_ID if !Docuseal.multitenant? && !account.testing? + + exists_access = TemplateAccess.where(TemplateAccess.arel_table[:template_id].eq(Template.arel_table[:id])) + .select(1).arel.exists + + Template.where(id: TemplateSharing.where(account_id: shared_account_ids).select(:template_id)) + .where.not(exists_access) + end + def search(current_user, templates, keyword) if Docuseal.fulltext_search? fulltext_search(current_user, templates, keyword)