mirror of
				https://github.com/scinote-eln/scinote-web.git
				synced 2025-10-31 16:49:40 +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
				
			
		|  | @ -842,7 +842,11 @@ function changeToEditMode() { | ||||||
|           $('#samples').data('num-columns', |           $('#samples').data('num-columns', | ||||||
|             $('#samples').data('num-columns') + 1); |             $('#samples').data('num-columns') + 1); | ||||||
|           originalHeader.append( |           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>'); |             data.name + '</th>'); | ||||||
|           var colOrder = table.colReorder.order(); |           var colOrder = table.colReorder.order(); | ||||||
|           colOrder.push(colOrder.length); |           colOrder.push(colOrder.length); | ||||||
|  | @ -916,6 +920,8 @@ function changeToEditMode() { | ||||||
|           '<li ' + |           '<li ' + | ||||||
|           'data-position="' + colIndex + '" ' + |           'data-position="' + colIndex + '" ' + | ||||||
|           'data-id="' + $(el).attr('id') + '" ' + |           '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 + '"' + |           'class="' + visLi + '"' + | ||||||
|           '>' + |           '>' + | ||||||
|           '<i class="grippy"></i> ' + |           '<i class="grippy"></i> ' + | ||||||
|  | @ -1002,6 +1008,29 @@ function changeToEditMode() { | ||||||
|       columnEditMode = false; |       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)
 |     // On edit buttons click (bind onto master dropdown list)
 | ||||||
|     dropdownList.on('click', '.edit:not(.disabled)', function(event) { |     dropdownList.on('click', '.edit:not(.disabled)', function(event) { | ||||||
|       event.stopPropagation(); |       event.stopPropagation(); | ||||||
|  | @ -1040,28 +1069,19 @@ function changeToEditMode() { | ||||||
|     // On ok buttons click
 |     // On ok buttons click
 | ||||||
|     dropdownList.on('click', '.ok', function(event) { |     dropdownList.on('click', '.ok', function(event) { | ||||||
|       event.stopPropagation(); |       event.stopPropagation(); | ||||||
| 
 |  | ||||||
|       var self = $(this); |       var self = $(this); | ||||||
|       var li = self.closest('li'); |       var li = self.closest('li'); | ||||||
|       var id = li.attr('data-id'); |       editColumn(li); | ||||||
|       var text = li.find('.text'); |  | ||||||
|       var textEdit = li.find('.text-edit'); |  | ||||||
|       var newName = textEdit.val().trim(); |  | ||||||
| 
 |  | ||||||
|       $.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
 |     // 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
 |   // initialze dropdown after the table is loaded
 | ||||||
|   function initDropdown() { |   function initDropdown() { | ||||||
|     table.on('init.dt', function() { |     table.on('init.dt', function() { | ||||||
|  | @ -1088,6 +1192,7 @@ function changeToEditMode() { | ||||||
|       initSorting(); |       initSorting(); | ||||||
|       toggleColumnVisibility(); |       toggleColumnVisibility(); | ||||||
|       initEditColumns(); |       initEditColumns(); | ||||||
|  |       initDeleteColumns(); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,8 +1,9 @@ | ||||||
| class CustomFieldsController < ApplicationController | class CustomFieldsController < ApplicationController | ||||||
|   before_action :load_vars, only: :update |   before_action :load_vars, only: [:update, :destroy, :destroy_html] | ||||||
|   before_action :load_vars_nested, only: [:create] |   before_action :load_vars_nested, only: [:create, :destroy_html] | ||||||
|   before_action :check_create_permissions, only: [:create] |   before_action :check_create_permissions, only: :create | ||||||
|   before_action :check_update_permissions, only: :update |   before_action :check_update_permissions, only: :update | ||||||
|  |   before_action :check_destroy_permissions, only: [:destroy, :destroy_html] | ||||||
| 
 | 
 | ||||||
|   def create |   def create | ||||||
|     @custom_field = CustomField.new(custom_field_params) |     @custom_field = CustomField.new(custom_field_params) | ||||||
|  | @ -14,7 +15,13 @@ class CustomFieldsController < ApplicationController | ||||||
|         format.json do |         format.json do | ||||||
|           render json: { |           render json: { | ||||||
|             id: @custom_field.id, |             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 |           status: :ok | ||||||
|         end |         end | ||||||
|  | @ -41,10 +48,37 @@ class CustomFieldsController < ApplicationController | ||||||
|     end |     end | ||||||
|   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 |   private | ||||||
| 
 | 
 | ||||||
|   def load_vars |   def load_vars | ||||||
|     @custom_field = CustomField.find_by_id(params[:id]) |     @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 |     render_404 unless @custom_field | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -61,6 +95,10 @@ class CustomFieldsController < ApplicationController | ||||||
|     render_403 unless can_edit_custom_field(@custom_field) |     render_403 unless can_edit_custom_field(@custom_field) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def check_destroy_permissions | ||||||
|  |     render_403 unless can_delete_custom_field(@custom_field) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def custom_field_params |   def custom_field_params | ||||||
|     params.require(:custom_field).permit(:name) |     params.require(:custom_field).permit(:name) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ class CustomField < ActiveRecord::Base | ||||||
|   belongs_to :last_modified_by, |   belongs_to :last_modified_by, | ||||||
|              foreign_key: 'last_modified_by_id', |              foreign_key: 'last_modified_by_id', | ||||||
|              class_name: 'User' |              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 |   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/import_samples_modal" %> | ||||||
| <%= render partial: "samples/delete_samples_modal" %> | <%= render partial: "samples/delete_samples_modal" %> | ||||||
| <%= render partial: "samples/create_sample_group_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 --> | <!-- 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> | <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 %>" |             id="<%= cf.id %>" | ||||||
|             <%= 'data-editable' if can_edit_custom_field(cf) %> |             <%= 'data-editable' if can_edit_custom_field(cf) %> | ||||||
|             <%= 'data-deletable' if can_delete_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 %> |           <%= cf.name %> | ||||||
|         </th> |         </th> | ||||||
|  |  | ||||||
|  | @ -832,6 +832,13 @@ en: | ||||||
|     modal_add_custom_field: |     modal_add_custom_field: | ||||||
|       title_html: "Add new column to team <strong>%{organization}</strong>" |       title_html: "Add new column to team <strong>%{organization}</strong>" | ||||||
|       create: "Add new column" |       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: |     modal_add_new_sample_group: | ||||||
|       title_html: "Add new sample group to team <strong>%{organization}</strong>" |       title_html: "Add new sample group to team <strong>%{organization}</strong>" | ||||||
|       create: "Add new sample group" |       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 'sample_group_element', to: 'sample_groups#sample_group_element' | ||||||
|       get 'destroy_confirmation', to: 'sample_groups#destroy_confirmation' |       get 'destroy_confirmation', to: 'sample_groups#destroy_confirmation' | ||||||
|     end |     end | ||||||
|     resources :custom_fields, only: [:create, :update] |     resources :custom_fields, only: [:create, :update, :destroy] do | ||||||
|  |       get 'destroy_html' | ||||||
|  |     end | ||||||
|     member do |     member do | ||||||
|       post 'parse_sheet' |       post 'parse_sheet' | ||||||
|       post 'import_samples' |       post 'import_samples' | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue