diff --git a/app/controllers/experiments_controller.rb b/app/controllers/experiments_controller.rb index 1aff48317..6350dfe49 100644 --- a/app/controllers/experiments_controller.rb +++ b/app/controllers/experiments_controller.rb @@ -1,7 +1,7 @@ class ExperimentsController < ApplicationController include PermissionHelper before_action :set_experiment, except: [:new, :create] - before_action :set_project, only: [:new, :create] + 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. @@ -57,6 +57,7 @@ class ExperimentsController < ApplicationController if @experiment.save flash[:success] = t('experiments.update.success_flash', experiment: @experiment.name) + redirect_to canvas_experiment_path(@experiment) else flash[:alert] = t('experiments.update.error_flash') @@ -71,6 +72,7 @@ class ExperimentsController < ApplicationController if @experiment.save flash[:success] = t('experiments.archive.success_flash', experiment: @experiment.name) + redirect_to project_path(@experiment.project) else flash[:alert] = t('experiments.archive.error_flash') @@ -78,6 +80,27 @@ 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 do + render json: ::SampleDatatable.new(view_context, + @organization, + nil, + nil, + @experiment) + end + end + end + private def set_experiment @@ -86,7 +109,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/datatables/sample_datatable.rb b/app/datatables/sample_datatable.rb index c9f8b4f29..fcbd27fe1 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,25 +124,30 @@ 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.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) + 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 + (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 @@ -172,6 +182,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(&: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 +222,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/helpers/permission_helper.rb b/app/helpers/permission_helper.rb index 3cdc584af..8bfc6009c 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? && 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/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 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" %> + +