mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-03-29 08:25:41 +08:00
Add delete custom field functionality
This commit is contained in:
parent
7e32c13d27
commit
1a8b141b95
8 changed files with 209 additions and 26 deletions
app
assets/javascripts/samples
controllers
models
views
config
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
16
app/views/samples/_delete_custom_field_modal.html.erb
Normal file
16
app/views/samples/_delete_custom_field_modal.html.erb
Normal 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">×</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>
|
12
app/views/samples/_delete_custom_field_modal_body.html.erb
Normal file
12
app/views/samples/_delete_custom_field_modal_body.html.erb
Normal 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>
|
||||
|
||||
<%= 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 %>
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Add table
Reference in a new issue