From 9581e2751f59f0001bbeb96df44d6c57ad3e48d6 Mon Sep 17 00:00:00 2001 From: zmagod Date: Tue, 2 Aug 2016 08:44:07 +0200 Subject: [PATCH 1/5] fixes samples page for experiment level [fixes SCI-44] --- app/controllers/experiments_controller.rb | 22 ++++++++++++++++--- app/helpers/permission_helper.rb | 6 ++++- app/helpers/secondary_navigation_helper.rb | 4 ++++ app/views/experiments/samples.html.erb | 7 ++++++ .../shared/_secondary_navigation.html.erb | 8 +++++++ config/routes.rb | 5 ++++- 6 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 app/views/experiments/samples.html.erb diff --git a/app/controllers/experiments_controller.rb b/app/controllers/experiments_controller.rb index 1ef63c8b6..0da3fbecc 100644 --- a/app/controllers/experiments_controller.rb +++ b/app/controllers/experiments_controller.rb @@ -1,8 +1,8 @@ class ExperimentsController < ApplicationController include PermissionHelper before_action :set_experiment, except: [:new, :create] - before_action :set_project, only: [:new, :create] - before_action :check_view_permissions, only: [:canvas] + before_action :set_project, only: [:new, :create, :samples_index, :samples ] + # before_action :check_view_permissions, only: [:canvas] # except parameter could be used but it is not working. layout :choose_layout @@ -66,6 +66,22 @@ class ExperimentsController < ApplicationController end end + def samples + @samples_index_link = samples_index_experiment_path(@experiment, format: :json) + @organization = @experiment.project.organization + end + + def samples_index + @organization = @experiment.project.organization + + respond_to do |format| + format.html + format.json { + render json: ::SampleDatatable.new(view_context, @organization, @experiment, nil) + } + end + end + private def set_experiment @@ -74,7 +90,7 @@ class ExperimentsController < ApplicationController end def set_project - @project = Project.find_by_id(params[:project_id]) + @project = Project.find_by_id(params[:project_id]) || @experiment.project render_404 unless @project end diff --git a/app/helpers/permission_helper.rb b/app/helpers/permission_helper.rb index 162d332b3..f061a4ca7 100644 --- a/app/helpers/permission_helper.rb +++ b/app/helpers/permission_helper.rb @@ -140,7 +140,8 @@ module PermissionHelper :can_view_experiment, :can_view_experiment_archive, :can_archive_experiment, - :can_restore_experiment + :can_restore_experiment, + :can_view_experiment_samples ] do |proxy, *args, &block| if args[0] experiment = args[0] @@ -346,6 +347,9 @@ module PermissionHelper experiment.archived? and is_user_or_higher_of_project(experiment.project) end + def can_view_experiment_samples(experiment) + can_view_samples(experiment.project.organization) + end # ---- WORKFLOW PERMISSIONS ---- def can_edit_canvas(experiment) diff --git a/app/helpers/secondary_navigation_helper.rb b/app/helpers/secondary_navigation_helper.rb index a12c48af7..e867d3c4a 100644 --- a/app/helpers/secondary_navigation_helper.rb +++ b/app/helpers/secondary_navigation_helper.rb @@ -28,6 +28,10 @@ module SecondaryNavigationHelper action_name == 'module_archive' end + def is_experiment_samples? + action_name == 'samples' + end + def is_module_info? action_name == 'show' end diff --git a/app/views/experiments/samples.html.erb b/app/views/experiments/samples.html.erb new file mode 100644 index 000000000..4f5692ae9 --- /dev/null +++ b/app/views/experiments/samples.html.erb @@ -0,0 +1,7 @@ +<% provide(:head_title, raw(t("projects.samples.head_title", project: @experiment.name))) %> +<%= render partial: "shared/sidebar" %> +<%= render partial: "shared/secondary_navigation" %> + +
+ <%= render partial: "shared/samples" %> +
diff --git a/app/views/shared/_secondary_navigation.html.erb b/app/views/shared/_secondary_navigation.html.erb index 1b57b912d..6d3516adf 100644 --- a/app/views/shared/_secondary_navigation.html.erb +++ b/app/views/shared/_secondary_navigation.html.erb @@ -99,6 +99,14 @@ <% end %> <% elsif experiment_page? %> + <% if can_view_experiment_samples(@experiment) then %> +
  • "> + "> + + + +
  • + <% end %> <% if can_view_experiment(@experiment) then %>
  • "> "> diff --git a/config/routes.rb b/config/routes.rb index dabf2e151..41ac22cf9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -101,7 +101,7 @@ Rails.application.routes.draw do get 'users/edit', to: 'user_projects#index_edit' end - resources :experiments do + resources :experiments, only: :show do member do get 'canvas' # Overview/structure for single experiment get 'canvas/edit', to: 'canvas#edit' # AJAX-loaded canvas edit mode (from canvas) @@ -110,6 +110,9 @@ Rails.application.routes.draw do get 'canvas/small_zoom', to: 'canvas#small_zoom' # AJAX-loaded canvas zoom post 'canvas', to: 'canvas#update' # Save updated canvas action get 'module_archive' # Module archive for single experiment + get 'samples' # Samples for single project + post 'samples_index' # Renders sample datatable for single project (ajax action) + post :delete_samples, constraints: CommitParamRouting.new(MyModulesController::DELETE_SAMPLES), action: :delete_samples end end From f184ee3f2d666b84ac5f6b29e0460d7d287cc40c Mon Sep 17 00:00:00 2001 From: zmagod Date: Tue, 2 Aug 2016 09:13:30 +0200 Subject: [PATCH 2/5] fixing hound warnings --- app/controllers/experiments_controller.rb | 25 +++++++++++++++-------- config/routes.rb | 15 ++++++++++---- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/app/controllers/experiments_controller.rb b/app/controllers/experiments_controller.rb index 0da3fbecc..8bdbdab3d 100644 --- a/app/controllers/experiments_controller.rb +++ b/app/controllers/experiments_controller.rb @@ -1,8 +1,8 @@ class ExperimentsController < ApplicationController include PermissionHelper before_action :set_experiment, except: [:new, :create] - before_action :set_project, only: [:new, :create, :samples_index, :samples ] - # before_action :check_view_permissions, only: [:canvas] + before_action :set_project, only: [:new, :create, :samples_index, :samples] + before_action :check_view_permissions, only: [:canvas] # except parameter could be used but it is not working. layout :choose_layout @@ -26,7 +26,8 @@ class ExperimentsController < ApplicationController @experiment.last_modified_by = current_user @experiment.project = @project if @experiment.save - flash[:success] = t('experiments.create.success_flash', experiment: @experiment.name) + flash[:success] = t('experiments.create.success_flash', + experiment: @experiment.name) # have to change to experiments path redirect_to root_path else @@ -43,7 +44,8 @@ class ExperimentsController < ApplicationController @experiment.update_attributes(experiment_params) @experiment.last_modified_by = current_user if @experiment.save - flash[:success] = t('experiments.update.success_flash', experiment: @experiment.name) + flash[:success] = t('experiments.update.success_flash', + experiment: @experiment.name) # have to change to experiments path redirect_to root_path else @@ -57,7 +59,8 @@ class ExperimentsController < ApplicationController @experiment.archived_by = current_user @experiment.archived_on = DateTime.now if @experiment.save - flash[:success] = t('experiments.archive.success_flash', experiment: @experiment.name) + flash[:success] = t('experiments.archive.success_flash', + experiment: @experiment.name) # have to change to experiments path redirect_to root_path else @@ -67,7 +70,8 @@ class ExperimentsController < ApplicationController end def samples - @samples_index_link = samples_index_experiment_path(@experiment, format: :json) + @samples_index_link = samples_index_experiment_path(@experiment, + format: :json) @organization = @experiment.project.organization end @@ -76,9 +80,12 @@ class ExperimentsController < ApplicationController respond_to do |format| format.html - format.json { - render json: ::SampleDatatable.new(view_context, @organization, @experiment, nil) - } + format.json do + render json: ::SampleDatatable.new(view_context, + @organization, + @experiment, + nil) + end end end diff --git a/config/routes.rb b/config/routes.rb index 41ac22cf9..a7f87d10e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -104,15 +104,22 @@ Rails.application.routes.draw do resources :experiments, only: :show do member do get 'canvas' # Overview/structure for single experiment - get 'canvas/edit', to: 'canvas#edit' # AJAX-loaded canvas edit mode (from canvas) + # AJAX-loaded canvas edit mode (from canvas) + get 'canvas/edit', to: 'canvas#edit' get 'canvas/full_zoom', to: 'canvas#full_zoom' # AJAX-loaded canvas zoom - get 'canvas/medium_zoom', to: 'canvas#medium_zoom' # AJAX-loaded canvas zoom + # AJAX-loaded canvas zoom + get 'canvas/medium_zoom', to: 'canvas#medium_zoom' get 'canvas/small_zoom', to: 'canvas#small_zoom' # AJAX-loaded canvas zoom post 'canvas', to: 'canvas#update' # Save updated canvas action get 'module_archive' # Module archive for single experiment get 'samples' # Samples for single project - post 'samples_index' # Renders sample datatable for single project (ajax action) - post :delete_samples, constraints: CommitParamRouting.new(MyModulesController::DELETE_SAMPLES), action: :delete_samples + # Renders sample datatable for single project (ajax action) + post 'samples_index' + post :delete_samples, + constraints: CommitParamRouting.new( + MyModulesController::DELETE_SAMPLES + ), + action: :delete_samples end end From 57ac34e9f44ac729bb647611f4646113862924cf Mon Sep 17 00:00:00 2001 From: zmagod Date: Wed, 3 Aug 2016 12:57:51 +0200 Subject: [PATCH 3/5] add samples to experiment page [fixes SCI-43] --- app/controllers/experiments_controller.rb | 5 +- app/datatables/sample_datatable.rb | 59 +++++++++++++++++++++-- app/models/project.rb | 13 +++++ 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/app/controllers/experiments_controller.rb b/app/controllers/experiments_controller.rb index 8bdbdab3d..c8394100a 100644 --- a/app/controllers/experiments_controller.rb +++ b/app/controllers/experiments_controller.rb @@ -83,8 +83,9 @@ class ExperimentsController < ApplicationController format.json do render json: ::SampleDatatable.new(view_context, @organization, - @experiment, - nil) + nil, + nil, + @experiment) end end end diff --git a/app/datatables/sample_datatable.rb b/app/datatables/sample_datatable.rb index c9f8b4f29..7c3afb35f 100644 --- a/app/datatables/sample_datatable.rb +++ b/app/datatables/sample_datatable.rb @@ -5,11 +5,16 @@ class SampleDatatable < AjaxDatatablesRails::Base ASSIGNED_SORT_COL = "assigned" - def initialize(view, organization, project = nil, my_module = nil) + def initialize(view, + organization, + project = nil, + my_module = nil, + experiment = nil) super(view) @organization = organization @project = project @my_module = my_module + @experiment = experiment end # Define sortable columns, so 1st column will be sorted by attribute in sortable_columns[0] @@ -119,6 +124,7 @@ class SampleDatatable < AjaxDatatablesRails::Base if @my_module @assigned_samples = @my_module.samples + samples = samples .joins( "LEFT OUTER JOIN sample_my_modules ON @@ -129,7 +135,20 @@ class SampleDatatable < AjaxDatatablesRails::Base .references(:sample_my_modules) elsif @project @assigned_samples = @project.assigned_samples - ids = @project.my_modules.select(:id) + ids = @project.my_modules_ids + + samples = samples + .joins( + "LEFT OUTER JOIN sample_my_modules ON + (samples.id = sample_my_modules.sample_id AND + (sample_my_modules.my_module_id IN (#{ids}) OR + sample_my_modules.id IS NULL))" + ) + .references(:sample_my_modules) + elsif @experiment + @assigned_samples = @experiment.assigned_samples + ids = @experiment.my_modules.select(:id) + samples = samples .joins( "LEFT OUTER JOIN sample_my_modules ON @@ -172,6 +191,39 @@ class SampleDatatable < AjaxDatatablesRails::Base # Depending on the sort, order nulls first or # nulls last on sample_my_modules association records.order("sample_my_modules.id NULLS #{sort_null_direction(params[:order].values[0])}") + elsif @experiment + # A very elegant solution to sort assigned samples at a experiment level + + # grabs the ids of samples which has a modules that belongs to this project + assigned = Sample + .joins('LEFT OUTER JOIN "sample_my_modules" ON "sample_my_modules"."sample_id" = "samples"."id"') + .joins('LEFT OUTER JOIN "my_modules" ON "my_modules"."id" = "sample_my_modules"."my_module_id"') + .where('"my_modules"."experiment_id" = ?', @experiment.id) + .where('"my_modules"."nr_of_assigned_samples" > 0') + .select('"samples"."id"') + .distinct + + # grabs the ids that are not the previous one but are still of the same organization + unassigned = Sample + .where('"samples"."organization_id" = ?', @organization.id) + .where('"samples"."id" NOT IN (?)', assigned) + .select('"samples"."id"') + .distinct + + # check the input param and merge the two arrays of ids + if params[:order].values[0]["dir"] == "asc" + ids = assigned + unassigned + elsif params[:order].values[0]["dir"] == "desc" + ids = unassigned + assigned + end + ids = ids.collect { |s| s.id } + + # order the records by input ids + order_by_index = ActiveRecord::Base.send( + :sanitize_sql_array, + ["position((',' || samples.id || ',') in ?)", + ids.join(',') + ','] ) + records.where(id: ids).order(order_by_index) elsif @project # A very elegant solution to sort assigned samples at a project level @@ -179,7 +231,8 @@ class SampleDatatable < AjaxDatatablesRails::Base assigned = Sample .joins('LEFT OUTER JOIN "sample_my_modules" ON "sample_my_modules"."sample_id" = "samples"."id"') .joins('LEFT OUTER JOIN "my_modules" ON "my_modules"."id" = "sample_my_modules"."my_module_id"') - .where('"my_modules"."project_id" = ?', @project.id) + .joins('LEFT OUTER JOIN "experiments" ON "experiments"."id" = "my_modules"."experiment_id"') + .where('"experiments"."project_id" = ?', @project.id) .where('"my_modules"."nr_of_assigned_samples" > 0') .select('"samples"."id"') .distinct diff --git a/app/models/project.rb b/app/models/project.rb index e4fd29c8c..0cd9e3d73 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -126,4 +126,17 @@ class Project < ActiveRecord::Base organization.log(final) end + def assigned_samples + Sample.joins(:my_modules).where(my_modules: { + id: my_modules_ids.split(',') + }) + end + + def my_modules_ids + ids = active_experiments.map do |exp| + exp.my_modules.pluck(:id) if exp.my_modules + end + ids.delete_if { |i| i.flatten.empty? } + ids.join(', ') + end end From 9d4a67a5b6e2e83b4b4e57d3d85b92f5c2a59971 Mon Sep 17 00:00:00 2001 From: zmagod Date: Wed, 3 Aug 2016 13:11:46 +0200 Subject: [PATCH 4/5] Feed the Hound 2 --- app/datatables/sample_datatable.rb | 56 +++++++++++++++--------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/app/datatables/sample_datatable.rb b/app/datatables/sample_datatable.rb index 7c3afb35f..717137084 100644 --- a/app/datatables/sample_datatable.rb +++ b/app/datatables/sample_datatable.rb @@ -6,10 +6,10 @@ class SampleDatatable < AjaxDatatablesRails::Base ASSIGNED_SORT_COL = "assigned" def initialize(view, - organization, - project = nil, - my_module = nil, - experiment = nil) + organization, + project = nil, + my_module = nil, + experiment = nil) super(view) @organization = organization @project = project @@ -126,37 +126,37 @@ class SampleDatatable < AjaxDatatablesRails::Base @assigned_samples = @my_module.samples samples = samples - .joins( - "LEFT OUTER JOIN sample_my_modules ON - (samples.id = sample_my_modules.sample_id AND - (sample_my_modules.my_module_id = #{@my_module.id.to_s} OR - sample_my_modules.id IS NULL))" - ) - .references(:sample_my_modules) + .joins( + "LEFT OUTER JOIN sample_my_modules ON + (samples.id = sample_my_modules.sample_id AND + (sample_my_modules.my_module_id = #{@my_module.id.to_s} OR + sample_my_modules.id IS NULL))" + ) + .references(:sample_my_modules) elsif @project @assigned_samples = @project.assigned_samples ids = @project.my_modules_ids samples = samples - .joins( - "LEFT OUTER JOIN sample_my_modules ON - (samples.id = sample_my_modules.sample_id AND - (sample_my_modules.my_module_id IN (#{ids}) OR - sample_my_modules.id IS NULL))" - ) - .references(:sample_my_modules) + .joins( + "LEFT OUTER JOIN sample_my_modules ON + (samples.id = sample_my_modules.sample_id AND + (sample_my_modules.my_module_id IN (#{ids}) OR + sample_my_modules.id IS NULL))" + ) + .references(:sample_my_modules) elsif @experiment @assigned_samples = @experiment.assigned_samples ids = @experiment.my_modules.select(:id) samples = samples - .joins( - "LEFT OUTER JOIN sample_my_modules ON - (samples.id = sample_my_modules.sample_id AND - (sample_my_modules.my_module_id IN (#{ids.to_sql}) OR - sample_my_modules.id IS NULL))" - ) - .references(:sample_my_modules) + .joins( + "LEFT OUTER JOIN sample_my_modules ON + (samples.id = sample_my_modules.sample_id AND + (sample_my_modules.my_module_id IN (#{ids.to_sql}) OR + sample_my_modules.id IS NULL))" + ) + .references(:sample_my_modules) end # Make mappings of custom fields, so we have same id for every column @@ -211,12 +211,12 @@ class SampleDatatable < AjaxDatatablesRails::Base .distinct # check the input param and merge the two arrays of ids - if params[:order].values[0]["dir"] == "asc" + if params[:order].values[0]['dir'] == 'asc' ids = assigned + unassigned - elsif params[:order].values[0]["dir"] == "desc" + elsif params[:order].values[0]['dir'] == 'desc' ids = unassigned + assigned end - ids = ids.collect { |s| s.id } + ids = ids.collect(&:id) # order the records by input ids order_by_index = ActiveRecord::Base.send( From fd8187370e654a10ecc556464e9b462bc0b7f6f8 Mon Sep 17 00:00:00 2001 From: zmagod Date: Wed, 3 Aug 2016 13:16:51 +0200 Subject: [PATCH 5/5] Feed the Hound part 3 --- app/datatables/sample_datatable.rb | 39 ++++++++++++------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/app/datatables/sample_datatable.rb b/app/datatables/sample_datatable.rb index 717137084..fcbd27fe1 100644 --- a/app/datatables/sample_datatable.rb +++ b/app/datatables/sample_datatable.rb @@ -125,38 +125,29 @@ class SampleDatatable < AjaxDatatablesRails::Base if @my_module @assigned_samples = @my_module.samples - samples = samples - .joins( - "LEFT OUTER JOIN sample_my_modules ON - (samples.id = sample_my_modules.sample_id AND - (sample_my_modules.my_module_id = #{@my_module.id.to_s} OR - sample_my_modules.id IS NULL))" - ) - .references(:sample_my_modules) + samples = samples.joins("LEFT OUTER JOIN sample_my_modules ON + (samples.id = sample_my_modules.sample_id AND + (sample_my_modules.my_module_id = #{@my_module.id.to_s} OR + sample_my_modules.id IS NULL))") + .references(:sample_my_modules) elsif @project @assigned_samples = @project.assigned_samples ids = @project.my_modules_ids - samples = samples - .joins( - "LEFT OUTER JOIN sample_my_modules ON - (samples.id = sample_my_modules.sample_id AND - (sample_my_modules.my_module_id IN (#{ids}) OR - sample_my_modules.id IS NULL))" - ) - .references(:sample_my_modules) + samples = samples.joins("LEFT OUTER JOIN sample_my_modules ON + (samples.id = sample_my_modules.sample_id AND + (sample_my_modules.my_module_id IN (#{ids}) OR + sample_my_modules.id IS NULL))") + .references(:sample_my_modules) elsif @experiment @assigned_samples = @experiment.assigned_samples ids = @experiment.my_modules.select(:id) - samples = samples - .joins( - "LEFT OUTER JOIN sample_my_modules ON - (samples.id = sample_my_modules.sample_id AND - (sample_my_modules.my_module_id IN (#{ids.to_sql}) OR - sample_my_modules.id IS NULL))" - ) - .references(:sample_my_modules) + samples = samples.joins("LEFT OUTER JOIN sample_my_modules ON + (samples.id = sample_my_modules.sample_id AND + (sample_my_modules.my_module_id IN (#{ids.to_sql}) OR + sample_my_modules.id IS NULL))") + .references(:sample_my_modules) end # Make mappings of custom fields, so we have same id for every column