setup endpoint for repository_rows paging/search

This commit is contained in:
zmagod 2018-03-06 16:32:39 +01:00
parent 50ccec5007
commit fb66131e29
14 changed files with 335 additions and 7 deletions

View file

@ -5,11 +5,23 @@ class RepositoryRowsController < ApplicationController
before_action :load_info_modal_vars, only: :show
before_action :load_vars, only: %i(edit update)
before_action :load_repository, only: %i(create delete_records)
before_action :load_repository, only: %i(create delete_records index)
before_action :load_columns_mappings, only: :index
before_action :check_create_permissions, only: :create
before_action :check_edit_permissions, only: %i(edit update)
before_action :check_destroy_permissions, only: :delete_records
def index
@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)
@repository_row_count = records.repository_rows.count
@repository_rows = records.repository_rows.page(page).per(per_page)
end
def create
record = RepositoryRow.new(repository: @repository,
created_by: current_user,
@ -238,6 +250,17 @@ class RepositoryRowsController < ApplicationController
def load_repository
@repository = Repository.find_by_id(params[:repository_id])
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_create_permissions

View file

@ -0,0 +1,46 @@
module RepositoryDatatableHelper
include InputSanitizeHelper
def prepare_row_columns(repository_rows, repository, columns_mappings, team)
parsed_records = []
repository_rows.each do |record|
row = {
'DT_RowId': record.id,
'1': assigned_row(record),
'2': escape_input(record.name),
'3': I18n.l(record.created_at, format: :full),
'4': escape_input(record.created_by.full_name),
'recordEditUrl':
Rails.application.routes.url_helpers
.edit_repository_repository_row_path(repository,
record.id),
'recordUpdateUrl':
Rails.application.routes.url_helpers
.repository_repository_row_path(repository, record.id),
'recordInfoUrl':
Rails.application.routes.url_helpers.repository_row_path(record.id)
}
# Add custom columns
# byebug
record.repository_cells.each do |cell|
row[columns_mappings[cell.repository_column.id]] =
custom_auto_link(
display_tooltip(cell.value.data,
Constants::NAME_MAX_LENGTH),
simple_format: true,
team: team
)
end
parsed_records << row
end
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
end
end

View file

@ -12,6 +12,8 @@ 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

@ -13,7 +13,11 @@ class RepositoryListValue < ApplicationRecord
validates :repository_cell, presence: true
def formatted
return '' unless repository_list_item
data.to_s
end
def data
return nil unless repository_list_item
repository_list_item.data
end
end

View file

@ -0,0 +1,21 @@
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

@ -0,0 +1,73 @@
class RepositoryDatatableService
attr_reader :repository_rows
def initialize(repository, params, mappings)
@mappings = mappings
@repository = repository
process_query(params)
end
private
def process_query(params)
contitions = build_conditions(params)
if contitions[:search_value].present?
@repository_rows = search(contitions[:search_value])
else
@repository_rows = fetch_records
end
# byebug
end
def fetch_records
RepositoryRow.preload(:repository_columns,
:created_by,
repository_cells: :value)
.joins(:created_by)
.where(repository: @repository)
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)
end
def build_conditions(params)
search_value = params[:search][:value]
order_by_column = { column: params[:order][:column].to_i,
dir: params[:order][:dir] }
{ search_value: search_value, order_by_column: order_by_column }
end
def sortable_columns
sort_array = [
'assigned',
'RepositoryRow.name',
'RepositoryRow.created_at',
'User.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'
end
array
end
end

View file

@ -0,0 +1,6 @@
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)
end

View file

@ -75,7 +75,7 @@ Rails.application.configure do
config.assets.raise_runtime_errors = true
# Only log info and higher on development
config.log_level = :info
config.log_level = :debug
# Only allow Better Errors to work on trusted ip, use ifconfig to see which
# one you use and put it into application.yml!

View file

@ -449,7 +449,7 @@ Rails.application.routes.draw do
resources :repositories do
post 'repository_index',
to: 'repositories#repository_table_index',
to: 'repository_rows#index', # repository_rows#index repositories#repository_table_index
as: 'table_index',
defaults: { format: 'json' }
# Save repository table state

View file

@ -0,0 +1,5 @@
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: 20180207095200) do
ActiveRecord::Schema.define(version: 20180306074931) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -964,4 +964,65 @@ ActiveRecord::Schema.define(version: 20180207095200) 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

@ -0,0 +1,28 @@
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

View file

@ -18,7 +18,7 @@ RSpec.describe RepositoryListValue, type: :model do
it { should accept_nested_attributes_for(:repository_cell) }
end
describe '#data' do
describe '#formatted' do
let!(:repository) { create :repository }
let!(:repository_column) { create :repository_column, name: 'My column' }
let!(:repository_column) do
@ -32,7 +32,7 @@ RSpec.describe RepositoryListValue, type: :model do
}
end
it 'returns the data of a selected item' do
it 'returns the formatted data of a selected item' do
list_item = create :repository_list_item,
data: 'my item',
repository: repository,
@ -71,4 +71,58 @@ RSpec.describe RepositoryListValue, type: :model do
expect(repository_list_value.reload.formatted).to eq ''
end
end
describe '#data' do
let!(:repository) { create :repository }
let!(:repository_column) { create :repository_column, name: 'My column' }
let!(:repository_column) do
create :repository_column, data_type: :RepositoryListValue
end
let!(:repository_row) { create :repository_row, name: 'My row' }
let!(:repository_list_value) do
create :repository_list_value, repository_cell_attributes: {
repository_column: repository_column,
repository_row: repository_row
}
end
it 'returns the data of a selected item' do
list_item = create :repository_list_item,
data: 'my item',
repository: repository,
repository_column: repository_column
repository_list_value.repository_list_item = list_item
repository_list_value.save
expect(repository_list_value.reload.data).to eq 'my item'
end
it 'retuns only the the item related to the list' do
repository_row_two = create :repository_row, name: 'New row'
repository_list_value_two =
create :repository_list_value, repository_cell_attributes: {
repository_column: repository_column,
repository_row: repository_row_two
}
list_item = create :repository_list_item,
data: 'new item',
repository: repository,
repository_column: repository_column
repository_list_value.repository_list_item = list_item
expect(repository_list_value.reload.data).to_not eq 'my item'
expect(repository_list_value.data).to be_nil
end
it 'returns an empty string if no item selected' do
list_item = create :repository_list_item,
data: 'my item',
repository: repository,
repository_column: repository_column
expect(repository_list_value.reload.data).to be_nil
end
it 'returns an empty string if item does not exists' do
repository_list_value.repository_list_item = nil
expect(repository_list_value.reload.data).to be_nil
end
end
end

View file

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe SearchRepository, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end