Add delete custom field functionality

This commit is contained in:
Luka Murn 2016-12-09 11:58:10 +01:00
parent 7e32c13d27
commit 1a8b141b95
8 changed files with 209 additions and 26 deletions

View file

@ -842,7 +842,11 @@ function changeToEditMode() {
$('#samples').data('num-columns',
$('#samples').data('num-columns') + 1);
originalHeader.append(
'<th class="custom-field" id="' + data.id + '" data-editable data-deletable>' +
'<th class="custom-field" id="' + data.id + '" ' +
'data-editable data-deletable ' +
'data-edit-url="' + data.edit_url + '" ' +
'data-destroy-html-url="' + data.destroy_html_url + '"' +
'>' +
data.name + '</th>');
var colOrder = table.colReorder.order();
colOrder.push(colOrder.length);
@ -916,6 +920,8 @@ function changeToEditMode() {
'<li ' +
'data-position="' + colIndex + '" ' +
'data-id="' + $(el).attr('id') + '" ' +
'data-edit-url=' + $(el).attr('data-edit-url') + ' ' +
'data-destroy-html-url=' + $(el).attr('data-destroy-html-url') + ' ' +
'class="' + visLi + '"' +
'>' +
'<i class="grippy"></i> ' +
@ -1002,6 +1008,29 @@ function changeToEditMode() {
columnEditMode = false;
}
function editColumn(li) {
var id = li.attr('data-id');
var text = li.find('.text');
var textEdit = li.find('.text-edit');
var newName = textEdit.val().trim();
var url = li.attr('data-edit-url');
$.ajax({
url: url,
type: 'PUT',
data: {custom_field: {name: newName}},
dataType: 'json',
success: function() {
text.text(newName);
$(table.columns().header()).filter('#' + id).text(newName);
cancelEditMode();
},
error: function(xhr) {
// TODO
}
});
}
// On edit buttons click (bind onto master dropdown list)
dropdownList.on('click', '.edit:not(.disabled)', function(event) {
event.stopPropagation();
@ -1040,28 +1069,19 @@ function changeToEditMode() {
// On ok buttons click
dropdownList.on('click', '.ok', function(event) {
event.stopPropagation();
var self = $(this);
var li = self.closest('li');
var id = li.attr('data-id');
var text = li.find('.text');
var textEdit = li.find('.text-edit');
var newName = textEdit.val().trim();
editColumn(li);
});
$.ajax({
url: '/organizations/1/custom_fields/' + id,
type: 'PUT',
data: {custom_field: {name: newName}},
dataType: 'json',
success: function() {
text.text(newName);
$(table.columns().header()).filter('#' + id).text(newName);
cancelEditMode();
},
error: function(xhr) {
// TODO
}
});
// On enter click while editing column text
dropdownList.on('keydown', 'input.text-edit', function(event) {
if (event.keyCode === 13) {
event.preventDefault();
var self = $(this);
var li = self.closest('li');
editColumn(li);
}
});
// On cancel buttons click
@ -1080,6 +1100,90 @@ function changeToEditMode() {
});
}
function initDeleteColumns() {
var modal = $('#deleteCustomField');
dropdownList.on('click', '.del', function(event) {
event.stopPropagation();
var self = $(this);
var li = self.closest('li');
var url = li.attr('data-destroy-html-url');
$.ajax({
url: url,
type: 'GET',
dataType: 'json',
success: function(data) {
var modalBody = modal.find('.modal-body');
// Inject the body's HTML into modal
modalBody.html(data.html);
// Show the modal
modal.modal('show');
},
error: function(xhr) {
// TODO
}
});
});
modal.find('.modal-footer [data-action=delete]').on('click', function() {
var modalBody = modal.find('.modal-body');
var form = modalBody.find('[data-role=destroy-custom-field-form]');
var id = form.attr('data-id');
form
.on('ajax:success', function() {
// Destroy datatable
table.destroy();
// Subtract number of columns
$('#samples').data(
'num-columns',
$('#samples').data('num-columns') - 1
);
// Remove column from table (=table header) & rows
var th = originalHeader.find('#' + id);
var index = th.index();
th.remove();
$('#samples tbody td:nth-child(' + (index + 1) + ')').remove();
// Remove all event handlers as we re-initialize them later with
// new table
$('#samples').off();
$('#samples thead').empty();
$('#samples thead').append(originalHeader);
// Preserve save/delete buttons as we need them after new table
// will be created
$('div.toolbarButtons').appendTo('div.samples-table');
$('div.toolbarButtons').hide();
// Re-initialize datatable
table = dataTableInit();
loadColumnsNames();
// Hide modal
modal.modal('hide');
})
.on('ajax:error', function() {
// TODO
});
form.submit();
});
modal.on('hidden.bs.modal', function() {
// Remove event handlers, clear contents
var modalBody = modal.find('.modal-body');
modalBody.off();
modalBody.html('');
});
}
// initialze dropdown after the table is loaded
function initDropdown() {
table.on('init.dt', function() {
@ -1088,6 +1192,7 @@ function changeToEditMode() {
initSorting();
toggleColumnVisibility();
initEditColumns();
initDeleteColumns();
});
}

View file

@ -1,8 +1,9 @@
class CustomFieldsController < ApplicationController
before_action :load_vars, only: :update
before_action :load_vars_nested, only: [:create]
before_action :check_create_permissions, only: [:create]
before_action :load_vars, only: [:update, :destroy, :destroy_html]
before_action :load_vars_nested, only: [:create, :destroy_html]
before_action :check_create_permissions, only: :create
before_action :check_update_permissions, only: :update
before_action :check_destroy_permissions, only: [:destroy, :destroy_html]
def create
@custom_field = CustomField.new(custom_field_params)
@ -14,7 +15,13 @@ class CustomFieldsController < ApplicationController
format.json do
render json: {
id: @custom_field.id,
name: @custom_field.name
name: @custom_field.name,
edit_url:
organization_custom_field_path(@organization, @custom_field),
destroy_html_url:
organization_custom_field_destroy_html_path(
@organization, @custom_field
)
},
status: :ok
end
@ -41,10 +48,37 @@ class CustomFieldsController < ApplicationController
end
end
def destroy_html
respond_to do |format|
format.json do
render json: {
html: render_to_string(
partial: 'samples/delete_custom_field_modal_body.html.erb'
)
}
end
end
end
def destroy
respond_to do |format|
format.json do
if @custom_field.destroy
render json: { status: :ok }
else
render json: { status: :unprocessable_entity }
end
end
end
end
private
def load_vars
@custom_field = CustomField.find_by_id(params[:id])
@custom_field = CustomField.find_by_id(
params[:custom_field_id]
) unless @custom_field
render_404 unless @custom_field
end
@ -61,6 +95,10 @@ class CustomFieldsController < ApplicationController
render_403 unless can_edit_custom_field(@custom_field)
end
def check_destroy_permissions
render_403 unless can_delete_custom_field(@custom_field)
end
def custom_field_params
params.require(:custom_field).permit(:name)
end

View file

@ -13,7 +13,7 @@ class CustomField < ActiveRecord::Base
belongs_to :last_modified_by,
foreign_key: 'last_modified_by_id',
class_name: 'User'
has_many :sample_custom_fields, inverse_of: :custom_field
has_many :sample_custom_fields, inverse_of: :custom_field, dependent: :destroy
after_create :update_samples_table_state

View file

@ -0,0 +1,16 @@
<div class="modal fade" id="deleteCustomField" tabindex="-1" role="dialog" aria-labelledby="deleteCustomFieldLabel">
<div class="modal-dialog" role="document">
<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>
<h4 class="modal-title"><%= t("samples.modal_delete_custom_field.title") %></h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-action="delete"><%= t("samples.modal_delete_custom_field.delete") %></button>
<button type="button" class="btn btn-default" data-dismiss="modal"><%= t("general.cancel")%></button>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,12 @@
<%= bootstrap_form_for @custom_field, url: organization_custom_field_path(@organization, @custom_field, format: :json), remote: :true, method: :delete, data: { role: "destroy-custom-field-form", id: @custom_field.id } do |f| %>
<p><%= t("samples.modal_delete_custom_field.message", cf: @custom_field.name) %></p>
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign"></span>
&nbsp;
<%= t("samples.modal_delete_custom_field.alert_heading") %>
<ul>
<li><%= t("samples.modal_delete_custom_field.alert_line_1", nr: @custom_field.sample_custom_fields.count) %></li>
<li><%= t("samples.modal_delete_custom_field.alert_line_2") %></li>
</ul>
</div>
<% end %>

View file

@ -1,6 +1,7 @@
<%= render partial: "samples/import_samples_modal" %>
<%= render partial: "samples/delete_samples_modal" %>
<%= render partial: "samples/create_sample_group_modal" %>
<%= render partial: "samples/delete_custom_field_modal" %>
<!-- Modal for parsing sample sheets should be empty at first -->
<div class="modal fade" id="modal-parse-samples" tabindex="-1" role="dialog" aria-labelledby=="modal-parse-samples-label"></div>
@ -140,6 +141,8 @@
id="<%= cf.id %>"
<%= 'data-editable' if can_edit_custom_field(cf) %>
<%= 'data-deletable' if can_delete_custom_field(cf) %>
<%= "data-edit-url='#{organization_custom_field_path(@organization, cf)}'" %>
<%= "data-destroy-html-url='#{organization_custom_field_destroy_html_path(@organization, cf)}'" %>
>
<%= cf.name %>
</th>

View file

@ -832,6 +832,13 @@ en:
modal_add_custom_field:
title_html: "Add new column to team <strong>%{organization}</strong>"
create: "Add new column"
modal_delete_custom_field:
title: "Delete a column"
message: "Are you sure you wish to permanently delete selected column %{cf}? This action is irreversible."
alert_heading: "Deleting a column has following consequences:"
alert_line_1: "you will lose information in this column for %{nr} samples;"
alert_line_2: "the column will be deleted for all team members."
delete: "Delete column"
modal_add_new_sample_group:
title_html: "Add new sample group to team <strong>%{organization}</strong>"
create: "Add new sample group"

View file

@ -79,7 +79,9 @@ Rails.application.routes.draw do
get 'sample_group_element', to: 'sample_groups#sample_group_element'
get 'destroy_confirmation', to: 'sample_groups#destroy_confirmation'
end
resources :custom_fields, only: [:create, :update]
resources :custom_fields, only: [:create, :update, :destroy] do
get 'destroy_html'
end
member do
post 'parse_sheet'
post 'import_samples'