fix assigned ordering

This commit is contained in:
zmagod 2018-03-08 17:36:10 +01:00
parent fb66131e29
commit 26883af386
11 changed files with 200 additions and 187 deletions

View file

@ -12,9 +12,11 @@ class MyModulesController < ApplicationController
toggle_task_state samples_index archive
complete_my_module repository repository_index
assign_repository_records unassign_repository_records]
before_action :load_vars_nested, only: %I[new create]
before_action :load_repository, only: %I[assign_repository_records
unassign_repository_records]
before_action :load_vars_nested, only: %i(new create)
before_action :load_repository, only: %i(assign_repository_records
unassign_repository_records
repository_index)
before_action :load_columns_mappings, only: :repository_index
before_action :check_manage_permissions,
only: %i(update destroy description due_date)
before_action :check_view_info_permissions, only: :show
@ -366,20 +368,18 @@ class MyModulesController < ApplicationController
# AJAX actions
def repository_index
@repository = Repository.find_by_id(params[:repository_id])
if @repository.nil? || !can_read_team?(@repository.team)
render_403
else
respond_to do |format|
format.html
format.json do
render json: ::RepositoryDatatable.new(view_context,
@repository,
@my_module,
current_user)
end
end
end
@draw = params[:draw].to_i
per_page = params[:length] == '-1' ? 100 : params[:length].to_i
page = (params[:start].to_i / per_page) + 1
records = RepositoryDatatableService.new(@repository,
params,
@columns_mappings,
current_user,
@my_module)
@assigned_rows = records.assigned_rows
@repository_row_count = records.repository_rows.count
@repository_rows = records.repository_rows.page(page).per(per_page)
render 'repository_rows/index.json'
end
# Submit actions
@ -598,7 +598,18 @@ class MyModulesController < ApplicationController
def load_repository
@repository = Repository.find_by_id(params[:repository_id])
render_404 unless @repository && can_read_team?(@repository.team)
render_404 unless @repository
render_403 unless can_read_team?(@repository.team)
end
def load_columns_mappings
# Make mappings of custom columns, so we have same id for every column
i = 5
@columns_mappings = {}
@repository.repository_columns.order(:id).each do |column|
@columns_mappings[column.id] = i.to_s
i += 1
end
end
def check_manage_permissions

View file

@ -17,7 +17,9 @@ class RepositoryRowsController < ApplicationController
page = (params[:start].to_i / per_page) + 1
records = RepositoryDatatableService.new(@repository,
params,
@columns_mappings)
@columns_mappings,
current_user)
@assigned_rows = records.assigned_rows
@repository_row_count = records.repository_rows.count
@repository_rows = records.repository_rows.page(page).per(per_page)
end

View file

@ -1,11 +1,15 @@
module RepositoryDatatableHelper
include InputSanitizeHelper
def prepare_row_columns(repository_rows, repository, columns_mappings, team)
def prepare_row_columns(repository_rows,
repository,
columns_mappings,
team,
assigned_rows)
parsed_records = []
repository_rows.each do |record|
row = {
'DT_RowId': record.id,
'1': assigned_row(record),
'1': assigned_row(record, assigned_rows),
'2': escape_input(record.name),
'3': I18n.l(record.created_at, format: :full),
'4': escape_input(record.created_by.full_name),
@ -21,7 +25,6 @@ module RepositoryDatatableHelper
}
# Add custom columns
# byebug
record.repository_cells.each do |cell|
row[columns_mappings[cell.repository_column.id]] =
custom_auto_link(
@ -36,11 +39,11 @@ module RepositoryDatatableHelper
parsed_records
end
def assigned_row(record)
# if @assigned_rows && @assigned_rows.include?(record)
# "<span class='circle'>&nbsp;</span>"
# else
"<span class='circle disabled'>&nbsp;</span>"
# end
def assigned_row(record, assigned_rows)
if assigned_rows&.include?(record)
"<span class='circle'>&nbsp;</span>"
else
"<span class='circle disabled'>&nbsp;</span>"
end
end
end

View file

@ -12,8 +12,6 @@ class Repository < ApplicationRecord
inverse_of: :repository, dependent: :destroy
has_many :report_elements, inverse_of: :repository, dependent: :destroy
has_many :repository_list_items, inverse_of: :repository, dependent: :destroy
has_many :repository_searchable_rows,
class_name: '::Views::Datatables::SearchRepository'
auto_strip_attributes :name, nullify: false
validates :name,

View file

@ -8,6 +8,10 @@ class RepositoryCell < ActiveRecord::Base
validates :repository_row,
uniqueness: { scope: :repository_column }
belongs_to :repository_text_value, optional: true, foreign_key: :value_id
belongs_to :repository_date_value, optional: true, foreign_key: :value_id
belongs_to :repository_list_value, optional: true, foreign_key: :value_id
private
def repository_column_data_type

View file

@ -1,21 +0,0 @@
module Views
module Datatables
class SearchRepository < ApplicationRecord
belongs_to :repository
# def self.records(repository, search_value)
# # binding.pry
# # # where('repository_rows.repository_id', repository.id).to_a
# # where(repository_id: repository.id)
# # .where()
# end
private
# this isn't strictly necessary, but it will prevent
# rails from calling save, which would fail anyway.
def readonly?
true
end
end
end
end

View file

@ -1,73 +1,179 @@
class RepositoryDatatableService
attr_reader :repository_rows
attr_reader :repository_rows, :assigned_rows
def initialize(repository, params, mappings)
def initialize(repository, params, mappings, user, my_module = nil)
@mappings = mappings
@repository = repository
process_query(params)
@mappings = mappings
@user = user
@my_module = my_module
@params = params
process_query
end
private
def process_query(params)
contitions = build_conditions(params)
if contitions[:search_value].present?
@repository_rows = search(contitions[:search_value])
def process_query
contitions = build_conditions(@params)
order_obj = contitions[:order_by_column]
search_value = contitions[:search_value]
if search_value.present?
@repository_rows = sort_rows(order_obj, search(search_value))
else
@repository_rows = fetch_records
@repository_rows = sort_rows(order_obj, fetch_records)
end
# byebug
end
def fetch_records
RepositoryRow.preload(:repository_columns,
:created_by,
repository_cells: :value)
.joins(:created_by)
.where(repository: @repository)
repository_rows = RepositoryRow.preload(:repository_columns,
:created_by,
repository_cells: :value)
.joins(:created_by)
.where(repository: @repository)
if @my_module
@assigned_rows = @my_module.repository_rows
.preload(
:repository_columns,
:created_by,
repository_cells: :value
)
.joins(:created_by)
.where(repository: @repository)
return @assigned_rows if @params[:assigned] == 'assigned'
else
@assigned_rows = repository_rows.joins(
'INNER JOIN my_module_repository_rows ON
(repository_rows.id = my_module_repository_rows.repository_row_id)'
)
end
repository_rows
end
def search(value)
# binding.pry
filtered_rows = @repository.repository_searchable_rows.where(
'name ILIKE :value
OR to_char(created_at, :time) ILIKE :value
OR user_full_name ILIKE :value
OR text_value ILIKE :value
OR date_value ILIKE :value
OR list_value ILIKE :value',
value: "%#{value}%",
time: "DD.MM.YYYY HH24:MI"
).pluck(:id)
fetch_records.where(id: filtered_rows)
includes_json = {
repository_cells: [:repository_text_value,
repository_list_value: :repository_list_item ]
}
RepositoryRow .left_outer_joins(:created_by)
.left_outer_joins(includes_json)
.where(repository: @repository)
.where_attributes_like(
['repository_rows.name',
'users.full_name',
'repository_text_values.data',
'repository_list_items.data'],
value
)
end
def build_conditions(params)
search_value = params[:search][:value]
order_by_column = { column: params[:order][:column].to_i,
dir: params[:order][:dir] }
order = params[:order].values.first
order_by_column = { column: order[:column].to_i,
dir: order[:dir] }
{ search_value: search_value, order_by_column: order_by_column }
end
def sortable_columns
sort_array = [
array = [
'assigned',
'RepositoryRow.name',
'RepositoryRow.created_at',
'User.full_name'
'repository_rows.name',
'repository_rows.created_at',
'users.full_name'
]
sort_array.push(*repository_columns_sort_by)
@sortable_columns = sort_array
end
def repository_columns_sort_by
array = []
@repository.repository_columns.count.times do
array << 'RepositoryCell.value'
array << 'repository_cell.value'
end
array
end
def sort_rows(column_obj, records)
dir = %w[DESC ASC].find { |dir| dir == column_obj[:dir].upcase } || 'ASC'
column_index = column_obj[:column]
col_order = @repository.repository_table_states
.find_by_user_id(@user.id)
.state['ColReorder']
column_id = col_order[column_index].to_i
if sortable_columns[column_id - 1] == 'assigned'
return records if @my_module && @params[:assigned] == 'assigned'
if @my_module
# Depending on the sort, order nulls first or
# nulls last on repository_cells association
return records.joins(
"LEFT OUTER JOIN my_module_repository_rows ON
(repository_rows.id = my_module_repository_rows.repository_row_id
AND (my_module_repository_rows.my_module_id = #{@my_module.id} OR
my_module_repository_rows.id IS NULL))"
).order(
"my_module_repository_rows.id NULLS #{sort_null_direction(dir)}"
)
else
return sort_assigned_records(records, dir)
end
elsif sortable_columns[column_id - 1] == 'repository_cell.value'
id = @mappings.key(column_id.to_s)
type = RepositoryColumn.find_by_id(id)
return records unless type
return select_type(type.data_type, records, id, dir)
else
return records.order("#{sortable_columns[column_id - 1]} #{dir}")
end
end
def sort_assigned_records(records, direction)
assigned = records.joins(:my_module_repository_rows).distinct.pluck(:id)
unassigned = records.where.not(id: assigned).pluck(:id)
if direction == 'ASC'
ids = assigned + unassigned
elsif direction == 'DESC'
ids = unassigned + assigned
end
order_by_index = ActiveRecord::Base.send(
:sanitize_sql_array,
["position((',' || repository_rows.id || ',') in ?)",
ids.join(',') + ',']
)
records.order(order_by_index)
end
def select_type(type, records, id, dir)
return filter_by_text_value(
records, id, dir) if type == 'RepositoryTextValue'
return filter_by_list_value(
records, id, dir) if type == 'RepositoryListValue'
end
def sort_null_direction(val)
val == 'ASC' ? 'LAST' : 'FIRST'
end
def filter_by_text_value(records, id, dir)
return records.joins(
"LEFT OUTER JOIN (SELECT repository_cells.repository_row_id,
repository_text_values.data AS value
FROM repository_cells
INNER JOIN repository_text_values
ON repository_text_values.id = repository_cells.value_id
WHERE repository_cells.repository_column_id = #{id}) AS values
ON values.repository_row_id = repository_rows.id"
).order("values.value #{dir}")
end
def filter_by_list_value(records, id, dir)
return records.joins(
"LEFT OUTER JOIN (SELECT repository_cells.repository_row_id,
repository_list_items.data AS value
FROM repository_cells
INNER JOIN repository_list_values
ON repository_list_values.id = repository_cells.value_id
INNER JOIN repository_list_items
ON repository_list_values.repository_list_item_id =
repository_list_items.id
WHERE repository_cells.repository_column_id = #{id}) AS values
ON values.repository_row_id = repository_rows.id"
).order("values.value #{dir}")
end
end

View file

@ -2,5 +2,9 @@ json.draw @draw
json.recordsTotal @repository_rows.total_count
json.recordsFiltered @repository_row_count
json.data do
json.array! prepare_row_columns(@repository_rows, @repository, @columns_mappings, @repository.team)
json.array! prepare_row_columns(@repository_rows,
@repository,
@columns_mappings,
@repository.team,
@assigned_rows)
end

View file

@ -1,5 +0,0 @@
class CreateSearchRepositories < ActiveRecord::Migration[5.1]
def change
create_view :search_repositories
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180306074931) do
ActiveRecord::Schema.define(version: 20180207095200) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -964,65 +964,4 @@ ActiveRecord::Schema.define(version: 20180306074931) do
JOIN user_teams ON ((teams.id = user_teams.team_id)));
SQL
create_view "search_repositories", sql_definition: <<-SQL
SELECT DISTINCT repository_rows.id,
repository_rows.repository_id,
repository_rows.created_by_id,
repository_rows.last_modified_by_id,
repository_rows.name,
repository_rows.created_at,
repository_rows.updated_at,
users.full_name AS user_full_name,
"values".text_value,
"values".date_value,
"values".list_value
FROM ((repository_rows
JOIN ( SELECT users_1.id,
users_1.full_name,
users_1.initials,
users_1.email,
users_1.encrypted_password,
users_1.reset_password_token,
users_1.reset_password_sent_at,
users_1.remember_created_at,
users_1.sign_in_count,
users_1.current_sign_in_at,
users_1.last_sign_in_at,
users_1.current_sign_in_ip,
users_1.last_sign_in_ip,
users_1.created_at,
users_1.updated_at,
users_1.avatar_file_name,
users_1.avatar_content_type,
users_1.avatar_file_size,
users_1.avatar_updated_at,
users_1.confirmation_token,
users_1.confirmed_at,
users_1.confirmation_sent_at,
users_1.unconfirmed_email,
users_1.invitation_token,
users_1.invitation_created_at,
users_1.invitation_sent_at,
users_1.invitation_accepted_at,
users_1.invitation_limit,
users_1.invited_by_type,
users_1.invited_by_id,
users_1.invitations_count,
users_1.tutorial_status,
users_1.current_team_id,
users_1.authentication_token,
users_1.settings
FROM users users_1) users ON ((users.id = repository_rows.created_by_id)))
LEFT JOIN ( SELECT repository_cells.repository_row_id,
repository_text_values.data AS text_value,
to_char(repository_date_values.data, 'DD.MM.YYYY HH24:MI'::text) AS date_value,
( SELECT repository_list_items.data
FROM repository_list_items
WHERE (repository_list_items.id = repository_list_values.repository_list_item_id)) AS list_value
FROM (((repository_cells
JOIN repository_text_values ON ((repository_text_values.id = repository_cells.value_id)))
FULL JOIN repository_date_values ON ((repository_date_values.id = repository_cells.value_id)))
FULL JOIN repository_list_values ON ((repository_list_values.id = repository_cells.value_id)))) "values" ON (("values".repository_row_id = repository_rows.id)));
SQL
end

View file

@ -1,28 +0,0 @@
SELECT DISTINCT
repository_rows.*,
users.full_name AS user_full_name,
values.text_value AS text_value,
values.date_value AS date_value,
values.list_value AS list_value
FROM repository_rows
INNER JOIN (
SELECT users.*
FROM users
) AS users
ON users.id = repository_rows.created_by_id
LEFT OUTER JOIN (
SELECT repository_cells.repository_row_id,
repository_text_values.data AS text_value,
to_char(repository_date_values.data, 'DD.MM.YYYY HH24:MI') AS date_value,
( SELECT repository_list_items.data
FROM repository_list_items
WHERE repository_list_items.id = repository_list_values.repository_list_item_id ) AS list_value
FROM repository_cells
INNER JOIN repository_text_values
ON repository_text_values.id = repository_cells.value_id
FULL OUTER JOIN repository_date_values
ON repository_date_values.id = repository_cells.value_id
FUll OUTER JOIN repository_list_values
ON repository_list_values.id = repository_cells.value_id
) AS values
ON values.repository_row_id = repository_rows.id