Merge pull request #3113 from mlorb/ml-sci-5311

Implement the option of deleting empty folders [SCI-5311]
This commit is contained in:
mlorb 2021-02-15 10:27:05 +01:00 committed by GitHub
commit 20dc9967f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 136 additions and 4 deletions

View file

@ -7,10 +7,10 @@
// - refresh project users tab after manage user modal is closed
// - refactor view handling using library, ex. backbone.js
/* global animateSpinner HelperModule dropdownSelector Sidebar Turbolinks filterDropdown */
/* global HelperModule dropdownSelector Sidebar Turbolinks filterDropdown */
(function() {
const PERMISSIONS = ['editable', 'archivable', 'restorable', 'moveable'];
const PERMISSIONS = ['editable', 'archivable', 'restorable', 'moveable', 'deletable'];
var projectsWrapper = '#projectsWrapper';
var toolbarWrapper = '#toolbarWrapper';
var cardsWrapper = '#cardsWrapper';
@ -97,6 +97,42 @@
});
}
// init delete project folders
function initDeleteFoldersToolbarButton() {
$(projectsWrapper)
.on('ajax:before', '.delete-folders-btn', function() {
let buttonForm = $(this);
buttonForm.find('input[name="project_folders_ids[]"]').remove();
selectedProjectFolders.forEach(function(id) {
$('<input>').attr({
type: 'hidden',
name: 'project_folders_ids[]',
value: id
}).appendTo(buttonForm);
});
})
.on('ajax:success', '.delete-folders-btn', function(ev, data) {
// Add and show modal
let deleteModal = $(data.html);
$(projectsWrapper).append(deleteModal);
deleteModal.modal('show');
// Remove modal when it gets closed
deleteModal.on('hidden.bs.modal', function() {
$(this).remove();
});
});
$(projectsWrapper)
.on('ajax:success', '.delete-folders-form', function(ev, data) {
$('.modal-project-folder-delete').modal('hide');
HelperModule.flashAlertMsg(data.message, 'success');
refreshCurrentView();
})
.on('ajax:error', '.delete-folders-form', function(ev, data) {
HelperModule.flashAlertMsg(data.responseJSON.message, 'danger');
});
}
// init project toolbar archive/restore functions
function initArchiveRestoreToolbarButtons() {
$(projectsWrapper)
@ -322,6 +358,8 @@
projectsToolbar.find('.single-object-action, .multiple-object-action').removeClass('hidden');
if (selectedProjectFolders.length === 1) {
projectsToolbar.find('.project-only-action').addClass('hidden');
} else {
projectsToolbar.find('.folders-only-action').addClass('hidden');
}
} else {
projectsToolbar.find('.single-object-action').addClass('hidden');
@ -329,6 +367,9 @@
if (selectedProjectFolders.length > 0) {
projectsToolbar.find('.project-only-action').addClass('hidden');
}
if (selectedProjects.length > 0) {
projectsToolbar.find('.folder-only-action').addClass('hidden');
}
}
PERMISSIONS.forEach((permission) => {
if (!checkActionPermission(permission)) {
@ -637,6 +678,7 @@
initManageUsersModal();
initExportProjectsModal();
initExportProjects();
initDeleteFoldersToolbarButton();
initArchiveRestoreToolbarButtons();
initViewProjectUsersLink();
initManageProjectUsersLink();

View file

@ -475,6 +475,11 @@ li.module-hover {
}
}
.delete-folders-form,
.delete-folders-btn {
display: inline-block;
}
.filter-container {
.projects-filters {
.select-block {

View file

@ -96,6 +96,35 @@ class ProjectFoldersController < ApplicationController
end
end
def destroy_modal
render json: {
html: render_to_string(partial: 'projects/index/modals/project_folder_delete.html.erb',
locals: { project_folders_ids: params[:project_folders_ids] })
}
end
def destroy
project_folders = current_team.project_folders.where(id: params[:project_folders_ids])
counter = 0
project_folders.each do |folder|
next if folder.projects.exists? || folder.project_folders.exists? || !can_update_team?(current_team)
folder.transaction do
log_activity(:delete_project_folder, folder, project_folder: folder.id)
folder.destroy!
counter += 1
rescue StandardError => e
Rails.logger.error e.message
raise ActiveRecord::Rollback
end
end
if counter.positive?
render json: { message: t('projects.delete_folders.success_flash', number: counter) }
else
render json: { message: t('projects.delete_folders.error_flash') }, status: :unprocessable_entity
end
end
private
def load_project_folder

View file

@ -97,3 +97,10 @@ Canaid::Permissions.register_for(ProjectComment) do
user.is_owner_of_project?(project_comment.project))
end
end
Canaid::Permissions.register_for(ProjectFolder) do
# ProjectFolder: delete
can :delete_project_folder do |_, project_folder|
!project_folder.projects.exists? && !project_folder.project_folders.exists?
end
end

View file

@ -4,7 +4,8 @@
data-editable="<%= can_update_team?(current_team) %>"
data-moveable="<%= can_update_team?(current_team) %>"
data-archivable="false"
data-restorable="false">
data-restorable="false"
data-deletable="<%= can_delete_project_folder?(folder) && can_update_team?(current_team) %>">
<div class="checkbox-cell table-cell">
<div class="sci-checkbox-container">
<input value="1" type="checkbox" class="sci-checkbox folder-card-selector">

View file

@ -46,6 +46,15 @@
<span class="fas fa-undo" aria-hidden="true"></span>
<span class="hidden-xs"><%= t('projects.index.restore_button') %></span>
<% end %>
<%= button_to destroy_modal_project_folders_url,
class: 'btn btn-light multiple-object-action folders-only-action hidden',
form_class: 'delete-folders-btn',
data: { for: :deletable },
remote: true,
method: :post do %>
<span class="fas fa-trash" aria-hidden="true"></span>
<span class="hidden-xs"><%= t('projects.index.delete_button') %></span>
<% end %>
<!-- export projects button -->
<a href="#" class="btn btn-light export-projects-btn multiple-object-action hidden"
data-export-projects-modal-url="<%= export_projects_modal_team_path(current_team) %>">

View file

@ -0,0 +1,25 @@
<div class="modal modal-project-folder-delete" role="dialog" aria-hidden="true" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h2 class="modal-title"><%= t('projects.index.modal_delete_folders.title') %></h2>
</div>
<div class="modal-body">
<p><%= t('projects.index.modal_delete_folders.description_1_html', number: project_folders_ids.size) %></p>
<p><%= t('projects.index.modal_delete_folders.description_2') %></p>
</div>
<div class="modal-footer">
<button type='button' class='btn btn-default' data-dismiss='modal'><%= t('general.cancel')%></button>
<%= button_to t('projects.index.modal_delete_folders.confirm_button'),
destroy_project_folders_path,
class: 'btn btn-danger',
form_class: 'delete-folders-form',
params: { project_folders_ids: project_folders_ids },
remote: true %>
</div>
</div>
</div>
</div>

View file

@ -380,7 +380,8 @@ class Extends
move_project: 158,
create_project_folder: 159,
move_project_folder: 160,
rename_project_folder: 161
rename_project_folder: 161,
delete_project_folder: 162
}
ACTIVITY_GROUPS = {

View file

@ -369,6 +369,7 @@ en:
move_button: "Move"
archive_button: "Archive"
restore_button: "Restore"
delete_button: "Delete"
edit_option: "Edit"
archive_option: "Archive"
archive_confirm: "Are you sure you want to archive this project?"
@ -417,6 +418,11 @@ en:
projects: 'projects'
folders: 'folders'
projects_and_folders: 'projects & folders'
modal_delete_folders:
title: "Delete project folder(s)"
description_1_html: "You are about to delete <strong>%{number}</strong> selected project folder(s)"
description_2: "Are you sure you want to continue?"
confirm_button: "Delete folder(s)"
modal_manage_users:
modal_title: "Manage users for %{name}"
no_users: "No users!"
@ -472,6 +478,9 @@ en:
restore:
success_flash: "Project <strong>%{name}</strong> successfully restored."
error_flash: "Project <strong>%{name}</strong> not restored."
delete_folders:
success_flash: "<strong>%{number}</strong> project folder(s) successfully deleted."
error_flash: "Failed to delete project folder(s)."
show:
head_title: "%{project}"
reports:

View file

@ -180,6 +180,7 @@ en:
create_project_folder_html: "%{user} created project folder %{project_folder}."
rename_project_folder_html: "%{user} renamed project folder %{project_folder}."
delete_project_folder_html: "%{user} deleted project folder %{project_folder}."
move_project_folder_html: "%{user} moved folder %{project_folder} from folder %{project_folder_from}</strong> to folder %{project_folder_to}."
activity_name:
@ -325,6 +326,7 @@ en:
move_project: "Project moved"
create_project_folder: "Project folder created"
rename_project_folder: "Project folder renamed"
delete_project_folder: "Project folder deleted"
move_project_folder: "Project folder moved"
activity_group:

View file

@ -310,6 +310,8 @@ Rails.application.routes.draw do
collection do
post 'move_to', to: 'project_folders#move_to', defaults: { format: 'json' }
get 'move_to_modal', to: 'project_folders#move_to_modal', defaults: { format: 'json' }
post 'destroy', to: 'project_folders#destroy', as: 'destroy', defaults: { format: 'json' }
post 'destroy_modal', to: 'project_folders#destroy_modal', defaults: { format: 'json' }
end
end
get 'project_folders/:project_folder_id', to: 'projects#index', as: :project_folder_projects