Merge branch 'mlorb-ml-sci-696' into improved-sample-table

Conflicts:
	app/assets/javascripts/samples/sample_datatable.js
This commit is contained in:
Mojca Lorber 2016-12-08 15:44:50 +01:00
commit 0e3526c9ad
12 changed files with 215 additions and 16 deletions

View file

@ -8,6 +8,11 @@ var currentMode = 'viewMode';
// Tells what action will execute by pressing on save button (update/create)
var saveAction = 'update';
var selectedSample;
// Helps saving correct table state
var myData;
var loadFirstTime = true;
var table;
var originalHeader;
@ -82,23 +87,57 @@ function dataTableInit() {
sampleInfoListener();
updateButtons();
},
stateSaveCallback: function(settings, data) {
// Set a cookie with the table state using the organization id
localStorage.setItem('datatables_state/' +
$('#samples').attr('data-organization-id'), JSON.stringify(data));
},
stateLoadCallback: function() {
// Load the table state for the current organization
var state = localStorage.getItem('datatables_state/' +
$('#samples').attr('data-organization-id'));
if (state !== null) {
return JSON.parse(state);
}
return null;
},
preDrawCallback: function() {
animateSpinner(this);
$('.sample_info').off('click');
$(".sample_info").off("click");
},
stateLoadCallback: function (settings) {
// Send an Ajax request to the server to get the data. Note that
// this is a synchronous request since the data is expected back from the
// function
var org = $("#samples").attr("data-organization-id")
var user = $("#samples").attr("data-user-id")
$.ajax( {
url: '/state_load/'+org+'/'+user,
data: {org: org},
async: false,
dataType: "json",
type: "POST",
success: function (json) {
myData = json.state;
}
} );
return myData
},
stateSaveCallback: function (settings, data) {
// Send an Ajax request to the server with the state object
var org = $("#samples").attr("data-organization-id")
var user = $("#samples").attr("data-user-id")
// Save correct data
if (loadFirstTime == true) {
data = myData;
}
$.ajax( {
url: '/state_save/'+org+'/'+user,
data: {org: org, state: data},
dataType: "json",
type: "POST"
} );
loadFirstTime = false;
},
fnInitComplete: function(oSettings, json) {
// Reload correct column order and visibility (if you refresh page)
oSettings._colReorder.fnOrder(myData.ColReorder);
for (var i = 0; i < table.columns()[0].length; i++) {
var visibility = myData.columns[i].visible;
if (typeof(visibility) === "string"){
var visibility = (visibility === "true");
}
table.column(i).visible(visibility);
}
}
});

View file

@ -0,0 +1,34 @@
class UserSamplesController < ApplicationController
def save_samples_table_status
samples_table = SamplesTable.where(user: @current_user,
organization: params[:org])
if samples_table
samples_table.first.update(status: params[:state])
else
SamplesTable.create(user: @current_user,
organization: params[:org],
status: params[:state])
end
respond_to do |format|
format.json do
render json: {
status: :ok
}
end
end
end
def load_samples_table_status
@samples_table_state = SamplesTable.find_status(current_user,
current_organization).first
respond_to do |format|
if @samples_table_state
format.json do
render json: {
state: @samples_table_state
}
end
end
end
end
end

View file

@ -3,7 +3,30 @@ require 'active_record'
class SampleDatatable < AjaxDatatablesRails::Base
include SamplesHelper
ASSIGNED_SORT_COL = "assigned"
ASSIGNED_SORT_COL = 'assigned'
SAMPLES_TABLE_DEFAULT_STATE = {
'time' => 0,
'start' => 0,
'length' => 10,
'order' => [[2, 'desc']],
'search' => { 'search' => '',
'smart' => true,
'regex' => false,
'caseInsensitive' => true },
'columns' => [],
'ColReorder' => [*0..6]
}
7.times do
SAMPLES_TABLE_DEFAULT_STATE['columns'] << {
'visible' => true,
'search' => { 'search' => '',
'smart' => true,
'regex' => false,
'caseInsensitive' => true }
}
end
SAMPLES_TABLE_DEFAULT_STATE.freeze
def initialize(view,
organization,

View file

@ -14,4 +14,10 @@ class CustomField < ActiveRecord::Base
foreign_key: 'last_modified_by_id',
class_name: 'User'
has_many :sample_custom_fields, inverse_of: :custom_field
after_create :update_samples_table_state
def update_samples_table_state
SamplesTable.update_samples_table_state(self)
end
end

View file

@ -15,6 +15,7 @@ class Organization < ActiveRecord::Base
has_many :user_organizations, inverse_of: :organization, dependent: :destroy
has_many :users, through: :user_organizations
has_many :samples, inverse_of: :organization
has_many :samples_tables, inverse_of: :organization, dependent: :destroy
has_many :sample_groups, inverse_of: :organization
has_many :sample_types, inverse_of: :organization
has_many :logs, inverse_of: :organization

View file

@ -0,0 +1,34 @@
class SamplesTable < ActiveRecord::Base
validates :user, :organization, presence: true
belongs_to :user, inverse_of: :samples_tables
belongs_to :organization, inverse_of: :samples_tables
scope :find_status,
->(org, user) { where(user: user, organization: org).pluck(:status) }
def self.update_samples_table_state(custom_field)
samples_table = SamplesTable.where(user: custom_field.user,
organization: custom_field.organization)
org_status = samples_table.first['status']
index = org_status['columns'].count
org_status['columns'][index] = SampleDatatable::
SAMPLES_TABLE_DEFAULT_STATE['columns'].first
org_status['ColReorder'] << index
samples_table.first.update(status: org_status)
end
def self.create_samples_table_state(user_org)
default_columns_num = SampleDatatable::
SAMPLES_TABLE_DEFAULT_STATE['columns'].count
org_status = SampleDatatable::SAMPLES_TABLE_DEFAULT_STATE.deep_dup
user_org.organization.custom_fields.each_with_index do |_, index|
org_status['columns'] << SampleDatatable::
SAMPLES_TABLE_DEFAULT_STATE['columns'].first
org_status['ColReorder'] << (default_columns_num + index)
end
SamplesTable.create(user: user_org.user,
organization: user_org.organization,
status: org_status)
end
end

View file

@ -46,6 +46,7 @@ class User < ActiveRecord::Base
has_many :activities, inverse_of: :user
has_many :results, inverse_of: :user
has_many :samples, inverse_of: :user
has_many :samples_tables, inverse_of: :user, dependent: :destroy
has_many :steps, inverse_of: :user
has_many :custom_fields, inverse_of: :user
has_many :reports, inverse_of: :user

View file

@ -10,11 +10,16 @@ class UserOrganization < ActiveRecord::Base
belongs_to :organization, inverse_of: :user_organizations
before_destroy :destroy_associations
after_create :create_samples_table_state
def role_str
I18n.t("user_organizations.enums.role.#{role.to_s}")
end
def create_samples_table_state
SamplesTable.create_samples_table_state(self)
end
def destroy_associations
# Destroy the user from all organization's projects
organization.projects.each do |project|

View file

@ -120,6 +120,7 @@
<div class="samples-table">
<table id="samples" class="table"
data-organization-id="<%= @project.organization.id %>"
data-user-id="<%= @current_user.id %>"
data-source="<%= @samples_index_link %>"
data-num-columns="<%= num_of_columns %>"
data-new-sample="<%= new_organization_sample_path(organization_id: @organization) %>"

View file

@ -5,6 +5,17 @@ Rails.application.routes.draw do
root 'projects#index'
# Save sample table state
post '/state_save/:organization_id/:user_id',
to: 'user_samples#save_samples_table_status',
as: 'save_samples_table_status',
defaults: { format: 'json' }
post '/state_load/:organization_id/:user_id',
to: 'user_samples#load_samples_table_status',
as: 'load_samples_table_status',
defaults: { format: 'json' }
resources :activities, only: [:index]
get "forbidden", :to => "application#forbidden", as: "forbidden"

View file

@ -0,0 +1,33 @@
class CreateSamplesTables < ActiveRecord::Migration
def change
create_table :samples_tables do |t|
t.jsonb :status, null: false,
default: SampleDatatable::SAMPLES_TABLE_DEFAULT_STATE
# Foreign keys
t.references :user, null: false
t.references :organization, null: false
t.timestamps null: false
end
add_index :samples_tables, :user_id
add_index :samples_tables, :organization_id
User.find_each do |user|
next unless user.organizations
user.organizations.find_each do |org|
org_status = SampleDatatable::SAMPLES_TABLE_DEFAULT_STATE.deep_dup
next unless org.custom_fields
org.custom_fields.each_with_index do |_, index|
org_status['columns'] << { 'visible' => true,
'search' => { 'search' => '',
'smart' => true,
'regex' => false,
'caseInsensitive' => true } }
org_status['ColReorder'] << (7 + index)
end
SamplesTable.create(user: user, organization: org, status: org_status)
end
end
end
end

View file

@ -497,6 +497,17 @@ ActiveRecord::Schema.define(version: 20161125153600) do
add_index "samples", ["sample_type_id"], name: "index_samples_on_sample_type_id", using: :btree
add_index "samples", ["user_id"], name: "index_samples_on_user_id", using: :btree
create_table "samples_tables", force: :cascade do |t|
t.jsonb "status", default: {"time"=>0, "order"=>[[2, "desc"]], "start"=>0, "length"=>10, "search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "columns"=>[{"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}], "ColReorder"=>[0, 1, 2, 3, 4, 5, 6]}, null: false
t.integer "user_id", null: false
t.integer "organization_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "samples_tables", ["organization_id"], name: "index_samples_tables_on_organization_id", using: :btree
add_index "samples_tables", ["user_id"], name: "index_samples_tables_on_user_id", using: :btree
create_table "step_assets", force: :cascade do |t|
t.integer "step_id", null: false
t.integer "asset_id", null: false