mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-03-03 19:24:48 +08:00
setup endpoint for repository_rows paging/search
This commit is contained in:
parent
50ccec5007
commit
fb66131e29
14 changed files with 335 additions and 7 deletions
|
@ -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
|
||||
|
|
46
app/helpers/repository_datatable_helper.rb
Normal file
46
app/helpers/repository_datatable_helper.rb
Normal 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'> </span>"
|
||||
# else
|
||||
"<span class='circle disabled'> </span>"
|
||||
# end
|
||||
end
|
||||
end
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
21
app/models/views/datatables/search_repository.rb
Normal file
21
app/models/views/datatables/search_repository.rb
Normal 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
|
73
app/services/repository_datatable_service.rb
Normal file
73
app/services/repository_datatable_service.rb
Normal 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
|
6
app/views/repository_rows/index.json.jbuilder
Normal file
6
app/views/repository_rows/index.json.jbuilder
Normal 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
|
|
@ -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!
|
||||
|
|
|
@ -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
|
||||
|
|
5
db/migrate/20180306074931_create_search_repositories.rb
Normal file
5
db/migrate/20180306074931_create_search_repositories.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class CreateSearchRepositories < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
create_view :search_repositories
|
||||
end
|
||||
end
|
63
db/schema.rb
63
db/schema.rb
|
@ -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
|
||||
|
|
28
db/views/search_repositories_v01.sql
Normal file
28
db/views/search_repositories_v01.sql
Normal 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
|
|
@ -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
|
||||
|
|
5
spec/models/search_repository_spec.rb
Normal file
5
spec/models/search_repository_spec.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SearchRepository, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
Loading…
Reference in a new issue