diff --git a/app/assets/javascripts/projects/index.js b/app/assets/javascripts/projects/index.js index 25b257375..f680233ae 100644 --- a/app/assets/javascripts/projects/index.js +++ b/app/assets/javascripts/projects/index.js @@ -34,14 +34,14 @@ var projectsViewMode = 'cards'; var projectsViewFilter = $('.projects-view-filter.active').data('filter'); - var projectsViewFilterChanged = false; var projectsChanged = false; var projectsViewSort = $('#sortMenuDropdown a.disabled').data('sort'); var TABLE; - // Array with selected project IDs shared between both views + // Arrays with selected project and folder IDs shared between both views var selectedProjects = []; + var selectedProjectFolders = []; /** * Initialize the JS for new project modal to work. @@ -227,7 +227,8 @@ type: 'GET', dataType: 'json', data: { - project_ids: selectedProjects + project_ids: selectedProjects, + project_folder_ids: selectedProjectFolders }, success: function(data) { // Update modal title @@ -270,7 +271,8 @@ type: 'POST', dataType: 'json', data: { - project_ids: selectedProjects + project_ids: selectedProjects, + project_folder_ids: selectedProjectFolders }, success: function(data) { // Hide modal and show success flash @@ -350,6 +352,22 @@ }); } + function refreshProjectsToolbar() { + let projectsToolbar = $('#projectsToolbar'); + + if (selectedProjects.length === 0 && selectedProjectFolders.length === 0) { + projectsToolbar.find('.single-project-action, .multiple-projects-action').addClass('hidden'); + projectsToolbar.find('.new-project-actions').removeClass('hidden'); + } else if (selectedProjects.length === 1 && selectedProjectFolders.length === 0) { + projectsToolbar.find('.new-project-actions').addClass('hidden'); + projectsToolbar.find('.single-project-action, .multiple-projects-action').removeClass('hidden'); + } else { + projectsToolbar.find('.new-project-actions').addClass('hidden'); + projectsToolbar.find('.single-project-action').addClass('hidden'); + projectsToolbar.find('.multiple-projects-action').removeClass('hidden'); + } + } + /** * Initializes cards view */ @@ -385,36 +403,42 @@ initEditProjectButton($('.panel-project')); initArchiveRestoreButton($('.panel-project')); - $('#cards-wrapper').on('click', '.card-selector', function() { - var projectsToolbar = $('#projectsToolbar'); - var projectCard = $(this).closest('.card'); - var projectId = projectCard.data('id'); + $('#cards-wrapper').on('click', '.folder-card-selector', function() { + let folderCard = $(this).closest('.folder-card'); + let folderId = folderCard.data('id'); + let index = $.inArray(folderId, selectedProjectFolders); + + // If checkbox is checked and row ID is not in list of selected folder IDs + if (this.checked && index === -1) { + selectedProjectFolders.push(folderId); + exportProjectsBtn.removeAttr('disabled'); + // Otherwise, if checkbox is not checked and ID is in list of selected IDs + } else if (!this.checked && index !== -1) { + selectedProjectFolders.splice(index, 1); + } + + refreshProjectsToolbar(); + }); + + $('#cards-wrapper').on('click', '.project-card-selector', function() { + let projectsToolbar = $('#projectsToolbar'); + let projectCard = $(this).closest('.project-card'); + let projectId = projectCard.data('id'); // Determine whether ID is in the list of selected project IDs - var index = $.inArray(projectId, selectedProjects); + let index = $.inArray(projectId, selectedProjects); // If checkbox is checked and row ID is not in list of selected project IDs if (this.checked && index === -1) { $(this).closest('.panel-project').addClass('selected'); selectedProjects.push(projectId); exportProjectsBtn.removeAttr('disabled'); - $('projects-actions').addClass('hidden'); // Otherwise, if checkbox is not checked and ID is in list of selected IDs } else if (!this.checked && index !== -1) { $(this).closest('.panel-project').removeClass('selected'); selectedProjects.splice(index, 1); } - if (selectedProjects.length === 0) { - projectsToolbar.find('.single-project-action, .multiple-projects-action').addClass('hidden'); - projectsToolbar.find('.new-project-actions').removeClass('hidden'); - } else if (selectedProjects.length === 1) { - projectsToolbar.find('.new-project-actions').addClass('hidden'); - projectsToolbar.find('.single-project-action, .multiple-projects-action').removeClass('hidden'); - } else { - projectsToolbar.find('.new-project-actions').addClass('hidden'); - projectsToolbar.find('.single-project-action').addClass('hidden'); - projectsToolbar.find('.multiple-projects-action').removeClass('hidden'); - } + refreshProjectsToolbar(); selectedProjects.forEach(function(id) { if ($('#projects-cards-view').find(`.panel-project[data-id="${id}"]`).hasClass('project-folder')) { diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 0afd5e7dd..6ccd9b20a 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class TeamsController < ApplicationController -before_action :load_vars, only: %i(export_projects export_projects_modal) -before_action :check_export_projects_permissions, only: %i(export_projects_modal export_projects) + before_action :load_vars, only: %i(export_projects export_projects_modal) + before_action :check_export_projects_permissions, only: %i(export_projects_modal export_projects) def export_projects if current_user.has_available_exports? @@ -64,22 +66,30 @@ before_action :check_export_projects_permissions, only: %i(export_projects_modal end def export_projects_params - params.permit(:id, project_ids: []).to_h + params.permit(:id, project_ids: [], project_folder_ids: []) end def check_export_projects_permissions render_403 unless can_read_team?(@team) + @exp_projects = [] if export_projects_params[:project_ids] - @exp_projects = Project.where(id: export_projects_params[:project_ids]) - @exp_projects.each do |project| - render_403 unless can_export_project?(current_user, project) + @exp_projects = @team.project.where(id: export_projects_params[:project_ids]).to_a + end + if export_projects_params[:project_folder_ids] + folders = @team.project_folders.where(id: export_projects_params[:project_folder_ids]) + folders.each do |folder| + @exp_projects += folder.inner_projects end end + + @exp_projects.each do |project| + return render_403 unless can_export_project?(current_user, project) + end end def generate_export_projects_zip - ids = @exp_projects.where(team_id: @team).index_by(&:id) + ids = @exp_projects.index_by(&:id) options = { team: @team } zip = TeamZipExport.create(user: current_user) diff --git a/app/models/project_folder.rb b/app/models/project_folder.rb index 2099585a0..1a8d27241 100644 --- a/app/models/project_folder.rb +++ b/app/models/project_folder.rb @@ -18,6 +18,12 @@ class ProjectFolder < ApplicationRecord scope :top_level, -> { where(parent_folder: nil) } + def inner_projects + project_folders.map do |inner_folder| + projects + inner_folder.inner_projects + end.flatten + end + private def inherit_team_from_parent_folder diff --git a/app/views/projects/index/_folder_card.html.erb b/app/views/projects/index/_folder_card.html.erb index 984dc702d..34c93247c 100644 --- a/app/views/projects/index/_folder_card.html.erb +++ b/app/views/projects/index/_folder_card.html.erb @@ -1,7 +1,7 @@ -
+
- +
diff --git a/app/views/projects/index/_project_card.html.erb b/app/views/projects/index/_project_card.html.erb index 30063ebb7..e239acd47 100644 --- a/app/views/projects/index/_project_card.html.erb +++ b/app/views/projects/index/_project_card.html.erb @@ -1,7 +1,7 @@ -
+
- +