mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-05 20:54:27 +08:00
implement search on list items dropdown, update, create actions [fixes SCI-2070]
This commit is contained in:
parent
0baa7a1f99
commit
d69754af04
13 changed files with 299 additions and 41 deletions
2
Gemfile
2
Gemfile
|
@ -26,7 +26,7 @@ gem 'momentjs-rails', '~> 2.17.1'
|
||||||
# JS datetime picker
|
# JS datetime picker
|
||||||
gem 'bootstrap3-datetimepicker-rails', '~> 4.15.35'
|
gem 'bootstrap3-datetimepicker-rails', '~> 4.15.35'
|
||||||
# Select elements for Bootstrap
|
# Select elements for Bootstrap
|
||||||
gem 'bootstrap-select-rails', '~> 1.6.3'
|
gem 'bootstrap-select-rails', '~> 1.12.4'
|
||||||
gem 'uglifier', '>= 1.3.0'
|
gem 'uglifier', '>= 1.3.0'
|
||||||
# jQuery & plugins
|
# jQuery & plugins
|
||||||
gem 'jquery-turbolinks'
|
gem 'jquery-turbolinks'
|
||||||
|
|
|
@ -127,7 +127,7 @@ GEM
|
||||||
bootstrap-sass (3.3.7)
|
bootstrap-sass (3.3.7)
|
||||||
autoprefixer-rails (>= 5.2.1)
|
autoprefixer-rails (>= 5.2.1)
|
||||||
sass (>= 3.3.4)
|
sass (>= 3.3.4)
|
||||||
bootstrap-select-rails (1.6.3)
|
bootstrap-select-rails (1.12.4)
|
||||||
bootstrap3-datetimepicker-rails (4.15.35)
|
bootstrap3-datetimepicker-rails (4.15.35)
|
||||||
momentjs-rails (>= 2.8.1)
|
momentjs-rails (>= 2.8.1)
|
||||||
bootstrap_form (2.7.0)
|
bootstrap_form (2.7.0)
|
||||||
|
@ -518,7 +518,7 @@ DEPENDENCIES
|
||||||
better_errors
|
better_errors
|
||||||
binding_of_caller
|
binding_of_caller
|
||||||
bootstrap-sass (~> 3.3.5)
|
bootstrap-sass (~> 3.3.5)
|
||||||
bootstrap-select-rails (~> 1.6.3)
|
bootstrap-select-rails (~> 1.12.4)
|
||||||
bootstrap3-datetimepicker-rails (~> 4.15.35)
|
bootstrap3-datetimepicker-rails (~> 4.15.35)
|
||||||
bootstrap_form
|
bootstrap_form
|
||||||
bullet
|
bullet
|
||||||
|
|
|
@ -31,11 +31,12 @@
|
||||||
//= require tinymce-jquery
|
//= require tinymce-jquery
|
||||||
//= require jsPlumb-2.0.4-min
|
//= require jsPlumb-2.0.4-min
|
||||||
//= require jsnetworkx
|
//= require jsnetworkx
|
||||||
|
//= require dataTables.noSearchHidden
|
||||||
|
//= require bootstrap-select
|
||||||
//= require_directory ./sitewide
|
//= require_directory ./sitewide
|
||||||
//= require jquery.dataTables.yadcf
|
//= require jquery.dataTables.yadcf
|
||||||
//= require datatables
|
//= require datatables
|
||||||
//= require dataTables.noSearchHidden
|
//= require ajax-bootstrap-select.min
|
||||||
//= require bootstrap-select
|
|
||||||
//= require underscore
|
//= require underscore
|
||||||
//= require i18n.js
|
//= require i18n.js
|
||||||
//= require i18n/translations
|
//= require i18n/translations
|
||||||
|
|
|
@ -432,14 +432,20 @@ var RepositoryDatatable = (function(global) {
|
||||||
} else if ($(th).attr('id') === 'row-name') {
|
} else if ($(th).attr('id') === 'row-name') {
|
||||||
input = changeToInputField('repository_row', 'name', '');
|
input = changeToInputField('repository_row', 'name', '');
|
||||||
tr.appendChild(createTdElement(input));
|
tr.appendChild(createTdElement(input));
|
||||||
} else if ($(th).hasClass('repository-column')) {
|
} else if ($(th).hasClass('repository-column') &&
|
||||||
|
$(th).attr('data-type') === 'RepositoryTextValue') {
|
||||||
input = changeToInputField('repository_cell', th.attr('id'), '');
|
input = changeToInputField('repository_cell', th.attr('id'), '');
|
||||||
tr.appendChild(createTdElement(input));
|
tr.appendChild(createTdElement(input));
|
||||||
|
} else if ($(th).hasClass('repository-column') &&
|
||||||
|
$(th).attr('data-type') === 'RepositoryListValue') {
|
||||||
|
input = initialListItemsRequest($(th).attr('id'));
|
||||||
|
tr.appendChild(createTdElement(input));
|
||||||
} else {
|
} else {
|
||||||
// Column we don't care for, just add empty td
|
// Column we don't care for, just add empty td
|
||||||
tr.appendChild(createTdElement(''));
|
tr.appendChild(createTdElement(''));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('table' + TABLE_ID).prepend(tr);
|
$('table' + TABLE_ID).prepend(tr);
|
||||||
selectedRecord = tr;
|
selectedRecord = tr;
|
||||||
|
|
||||||
|
@ -451,6 +457,8 @@ var RepositoryDatatable = (function(global) {
|
||||||
});
|
});
|
||||||
// Adjust columns width in table header
|
// Adjust columns width in table header
|
||||||
adjustTableHeader();
|
adjustTableHeader();
|
||||||
|
// Init selectpicker
|
||||||
|
_initSelectPicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
global.onClickToggleAssignedRecords = function() {
|
global.onClickToggleAssignedRecords = function() {
|
||||||
|
@ -584,6 +592,7 @@ var RepositoryDatatable = (function(global) {
|
||||||
|
|
||||||
// Take care of custom cells
|
// Take care of custom cells
|
||||||
var cells = data.repository_row.repository_cells;
|
var cells = data.repository_row.repository_cells;
|
||||||
|
var list_columns = data.repository_row.repository_column_items;
|
||||||
$(node).children('td').each(function(i) {
|
$(node).children('td').each(function(i) {
|
||||||
var td = $(this);
|
var td = $(this);
|
||||||
var rawIndex = TABLE.column.index('fromVisible', i);
|
var rawIndex = TABLE.column.index('fromVisible', i);
|
||||||
|
@ -592,13 +601,17 @@ var RepositoryDatatable = (function(global) {
|
||||||
// Check if cell on this record exists
|
// Check if cell on this record exists
|
||||||
var cell = cells[$(colHeader).attr('id')];
|
var cell = cells[$(colHeader).attr('id')];
|
||||||
if (cell) {
|
if (cell) {
|
||||||
td.html(changeToInputField('repository_cell',
|
td.html(changeToFormField('repository_cell',
|
||||||
$(colHeader).attr('id'),
|
$(colHeader).attr('id'),
|
||||||
cell.value));
|
cell,
|
||||||
|
list_columns));
|
||||||
} else {
|
} else {
|
||||||
td.html(changeToInputField('repository_cell',
|
td.html(changeToFormField('repository_cell',
|
||||||
$(colHeader).attr('id'), ''));
|
$(colHeader).attr('id'),
|
||||||
|
'',
|
||||||
|
list_columns));
|
||||||
}
|
}
|
||||||
|
_initSelectPicker();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -647,13 +660,18 @@ var RepositoryDatatable = (function(global) {
|
||||||
// Record name
|
// Record name
|
||||||
data.repository_row.name = $('td input[data-object = repository_row]').val();
|
data.repository_row.name = $('td input[data-object = repository_row]').val();
|
||||||
|
|
||||||
// Custom cells
|
// Custom cells text type
|
||||||
$(node).find('td input[data-object = repository_cell]').each(function() {
|
$(node).find('td input[data-object = repository_cell]').each(function() {
|
||||||
// Send data only and only if cell is not empty
|
// Send data only and only if cell is not empty
|
||||||
if ($(this).val().trim()) {
|
if ($(this).val().trim()) {
|
||||||
data.repository_cells[$(this).attr('name')] = $(this).val();
|
data.repository_cells[$(this).attr('name')] = $(this).val();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Custom cells list type
|
||||||
|
$(node).find('td[column_id]').each(function(index, el) {
|
||||||
|
var value = $(el).attr('list_item_id');
|
||||||
|
data.repository_cells[$(el).attr('column_id')] = value;
|
||||||
|
});
|
||||||
|
|
||||||
var url;
|
var url;
|
||||||
var type;
|
var type;
|
||||||
|
@ -845,6 +863,88 @@ var RepositoryDatatable = (function(global) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
|
function _listItemDropdown(options, current_value, column_id) {
|
||||||
|
var html = '<select class="form-control selectpicker" ';
|
||||||
|
html += 'data-abs-min-length="2" data-live-search="true" ';
|
||||||
|
html += 'column_id="' + column_id +'">';
|
||||||
|
html += '<option value="-1"></option>';
|
||||||
|
$.each(options, function(index, value) {
|
||||||
|
var selected = (current_value === value[1]) ? 'selected' : '';
|
||||||
|
html += '<option value="' + value[0] + '" ' + selected + '>';
|
||||||
|
html += value[1] + '</option>';
|
||||||
|
});
|
||||||
|
html += '</select>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialListItemsRequest(column_id) {
|
||||||
|
var massage_response = [];
|
||||||
|
$.ajax({
|
||||||
|
url: '<%= Rails.application.routes.url_helpers.repository_list_items_path %>',
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
async: false,
|
||||||
|
data: {
|
||||||
|
q: '',
|
||||||
|
column_id: column_id
|
||||||
|
}
|
||||||
|
}).done(function(data) {
|
||||||
|
$.each(data.list_items, function(index, el) {
|
||||||
|
massage_response.push([el.id, el.data]);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
return _listItemDropdown(massage_response, '-1', column_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _initSelectPicker() {
|
||||||
|
$('.selectpicker')
|
||||||
|
.selectpicker({liveSearch: true})
|
||||||
|
.ajaxSelectPicker({
|
||||||
|
ajax: {
|
||||||
|
url: '<%= Rails.application.routes.url_helpers.repository_list_items_path %>',
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: function () {
|
||||||
|
var params = {
|
||||||
|
q: '{{{q}}}',
|
||||||
|
column_id: $(this.valueOf().plugin.$element).attr('column_id')
|
||||||
|
};
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
emptyTitle: 'Nothing selected'
|
||||||
|
},
|
||||||
|
preprocessData: function(data){
|
||||||
|
var items = [];
|
||||||
|
if(data.hasOwnProperty('list_items')){
|
||||||
|
items.push({
|
||||||
|
'value': '-1',
|
||||||
|
'text': '',
|
||||||
|
'disabled': false
|
||||||
|
});
|
||||||
|
$.each(data.list_items, function(index, el) {
|
||||||
|
items.push(
|
||||||
|
{
|
||||||
|
'value': el.id,
|
||||||
|
'text': el.data,
|
||||||
|
'disabled': false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
},
|
||||||
|
emptyRequest: true,
|
||||||
|
clearOnEmpty: false,
|
||||||
|
preserveSelected: false
|
||||||
|
}).on('change.bs.select', function(el) {
|
||||||
|
$(this).closest('td').attr('list_item_id', el.target.value);
|
||||||
|
$(this).closest('td').attr('column_id', $(this).attr('column_id'));
|
||||||
|
});;
|
||||||
|
}
|
||||||
|
|
||||||
function getColumnIndex(id) {
|
function getColumnIndex(id) {
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -858,6 +958,24 @@ var RepositoryDatatable = (function(global) {
|
||||||
object + "' name='" + name + "' value='" + value + "'></input></div>";
|
object + "' name='" + name + "' value='" + value + "'></input></div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Takes an object and creates custom html element
|
||||||
|
function changeToFormField(object, name, cell, list_columns) {
|
||||||
|
if (cell === '') {
|
||||||
|
var column = _.findWhere(list_columns, { column_id: parseInt(name) });
|
||||||
|
if (column) {
|
||||||
|
return _listItemDropdown(column.list_items, '', parseInt(name));
|
||||||
|
} else {
|
||||||
|
return changeToInputField(object, name, '');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cell.type === 'RepositoryListValue') {
|
||||||
|
return _listItemDropdown(cell.list_items, cell.value, parseInt(name));
|
||||||
|
} else {
|
||||||
|
return changeToInputField(object, name, cell.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return td element with content
|
// Return td element with content
|
||||||
function createTdElement(content) {
|
function createTdElement(content) {
|
||||||
var td = document.createElement('td');
|
var td = document.createElement('td');
|
|
@ -16,6 +16,7 @@
|
||||||
@import "bootstrap-tagsinput";
|
@import "bootstrap-tagsinput";
|
||||||
@import "bootstrap-tagsinput-typeahead";
|
@import "bootstrap-tagsinput-typeahead";
|
||||||
@import "handsontable.full.min";
|
@import "handsontable.full.min";
|
||||||
|
@import "ajax-bootstrap-select.min";
|
||||||
@import "extend/bootstrap";
|
@import "extend/bootstrap";
|
||||||
@import "font-awesome";
|
@import "font-awesome";
|
||||||
@import "themes/scinote";
|
@import "themes/scinote";
|
||||||
|
|
26
app/controllers/repository_list_items_controller.rb
Normal file
26
app/controllers/repository_list_items_controller.rb
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
class RepositoryListItemsController < ApplicationController
|
||||||
|
before_action :load_vars, only: :search
|
||||||
|
|
||||||
|
def search
|
||||||
|
column_list_items = @repository_column.repository_list_items
|
||||||
|
.where('data ILIKE ?',
|
||||||
|
"%#{search_params[:q]}%")
|
||||||
|
.limit(Constants::SEARCH_LIMIT)
|
||||||
|
.select(:id, :data)
|
||||||
|
|
||||||
|
render json: { list_items: column_list_items }, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def search_params
|
||||||
|
params.permit(:q, :column_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_vars
|
||||||
|
@repository_column = RepositoryColumn.find_by_id(search_params[:column_id])
|
||||||
|
repository = @repository_column.repository if @repository_column
|
||||||
|
render_404 and return unless @repository_column&.data_type == "RepositoryListValue"
|
||||||
|
render_403 unless can_manage_repository_rows?(repository.team)
|
||||||
|
end
|
||||||
|
end
|
|
@ -38,15 +38,31 @@ class RepositoryRowsController < ApplicationController
|
||||||
column = @repository.repository_columns.detect do |c|
|
column = @repository.repository_columns.detect do |c|
|
||||||
c.id == key.to_i
|
c.id == key.to_i
|
||||||
end
|
end
|
||||||
cell_value = RepositoryTextValue.new(
|
if column.data_type == 'RepositoryListValue'
|
||||||
data: value,
|
next if value == '-1'
|
||||||
created_by: current_user,
|
# check if item existx else revert the transaction
|
||||||
last_modified_by: current_user,
|
list_item = RepositoryListItem.where(repository_column: column)
|
||||||
repository_cell_attributes: {
|
.find(value)
|
||||||
repository_row: record,
|
cell_value = RepositoryListValue.new(
|
||||||
repository_column: column
|
repository_list_item_id: list_item.id,
|
||||||
}
|
created_by: current_user,
|
||||||
)
|
last_modified_by: current_user,
|
||||||
|
repository_cell_attributes: {
|
||||||
|
repository_row: record,
|
||||||
|
repository_column: column
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else
|
||||||
|
cell_value = RepositoryTextValue.new(
|
||||||
|
data: value,
|
||||||
|
created_by: current_user,
|
||||||
|
last_modified_by: current_user,
|
||||||
|
repository_cell_attributes: {
|
||||||
|
repository_row: record,
|
||||||
|
repository_column: column
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
if cell_value.save
|
if cell_value.save
|
||||||
record_annotation_notification(record, cell_value.repository_cell)
|
record_annotation_notification(record, cell_value.repository_cell)
|
||||||
else
|
else
|
||||||
|
@ -91,7 +107,8 @@ class RepositoryRowsController < ApplicationController
|
||||||
json = {
|
json = {
|
||||||
repository_row: {
|
repository_row: {
|
||||||
name: escape_input(@record.name),
|
name: escape_input(@record.name),
|
||||||
repository_cells: {}
|
repository_cells: {},
|
||||||
|
repository_column_items: fetch_columns_list_items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +116,9 @@ class RepositoryRowsController < ApplicationController
|
||||||
@record.repository_cells.each do |cell|
|
@record.repository_cells.each do |cell|
|
||||||
json[:repository_row][:repository_cells][cell.repository_column_id] = {
|
json[:repository_row][:repository_cells][cell.repository_column_id] = {
|
||||||
repository_cell_id: cell.id,
|
repository_cell_id: cell.id,
|
||||||
value: escape_input(cell.value.data)
|
value: escape_input(cell.value.data),
|
||||||
|
type: cell.value_type,
|
||||||
|
list_items: fetch_list_items(cell)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -125,14 +144,26 @@ class RepositoryRowsController < ApplicationController
|
||||||
end
|
end
|
||||||
if existing
|
if existing
|
||||||
# Cell exists and new value present, so update value
|
# Cell exists and new value present, so update value
|
||||||
existing.value.data = value
|
if existing.value_type == 'RepositoryListValue'
|
||||||
if existing.value.save
|
item = RepositoryListItem.where(
|
||||||
record_annotation_notification(@record, existing)
|
repository_column: existing.repository_column
|
||||||
|
).find(value) unless value == '-1'
|
||||||
|
if item
|
||||||
|
existing.repository_list_value
|
||||||
|
.update_attribute(:repository_list_item_id, item)
|
||||||
|
else
|
||||||
|
existing.delete
|
||||||
|
end
|
||||||
else
|
else
|
||||||
errors[:repository_cells] << {
|
existing.value.data = value
|
||||||
"#{existing.repository_column_id}":
|
if existing.value.save
|
||||||
existing.value.errors.messages
|
record_annotation_notification(@record, existing)
|
||||||
}
|
else
|
||||||
|
errors[:repository_cells] << {
|
||||||
|
"#{existing.repository_column_id}":
|
||||||
|
existing.value.errors.messages
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# Looks like it is a new cell, so we need to create new value, cell
|
# Looks like it is a new cell, so we need to create new value, cell
|
||||||
|
@ -140,15 +171,31 @@ class RepositoryRowsController < ApplicationController
|
||||||
column = @repository.repository_columns.detect do |c|
|
column = @repository.repository_columns.detect do |c|
|
||||||
c.id == key.to_i
|
c.id == key.to_i
|
||||||
end
|
end
|
||||||
cell_value = RepositoryTextValue.new(
|
if column.data_type == 'RepositoryListValue'
|
||||||
data: value,
|
next if value == '-1'
|
||||||
created_by: current_user,
|
# check if item existx else revert the transaction
|
||||||
last_modified_by: current_user,
|
list_item = RepositoryListItem.where(repository_column: column)
|
||||||
repository_cell_attributes: {
|
.find(value)
|
||||||
repository_row: @record,
|
cell_value = RepositoryListValue.new(
|
||||||
repository_column: column
|
repository_list_item_id: list_item.id,
|
||||||
}
|
created_by: current_user,
|
||||||
)
|
last_modified_by: current_user,
|
||||||
|
repository_cell_attributes: {
|
||||||
|
repository_row: @record,
|
||||||
|
repository_column: column
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else
|
||||||
|
cell_value = RepositoryTextValue.new(
|
||||||
|
data: value,
|
||||||
|
created_by: current_user,
|
||||||
|
last_modified_by: current_user,
|
||||||
|
repository_cell_attributes: {
|
||||||
|
repository_row: @record,
|
||||||
|
repository_column: column
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
if cell_value.save
|
if cell_value.save
|
||||||
record_annotation_notification(@record,
|
record_annotation_notification(@record,
|
||||||
cell_value.repository_cell)
|
cell_value.repository_cell)
|
||||||
|
@ -161,6 +208,7 @@ class RepositoryRowsController < ApplicationController
|
||||||
end
|
end
|
||||||
# Clean up empty cells, not present in updated record
|
# Clean up empty cells, not present in updated record
|
||||||
@record.repository_cells.each do |cell|
|
@record.repository_cells.each do |cell|
|
||||||
|
next if cell.value_type == 'RepositoryListValue'
|
||||||
cell.value.destroy unless cell_params
|
cell.value.destroy unless cell_params
|
||||||
.key?(cell.repository_column_id.to_s)
|
.key?(cell.repository_column_id.to_s)
|
||||||
end
|
end
|
||||||
|
@ -293,4 +341,28 @@ class RepositoryRowsController < ApplicationController
|
||||||
column: link_to(cell.repository_column.name, table_url))
|
column: link_to(cell.repository_column.name, table_url))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fetch_list_items(cell)
|
||||||
|
return [] if cell.value_type != 'RepositoryListValue'
|
||||||
|
RepositoryListItem.where(repository: @repository)
|
||||||
|
.where(repository_column: cell.repository_column)
|
||||||
|
.limit(Constants::SEARCH_LIMIT)
|
||||||
|
.pluck(:id, :data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_columns_list_items
|
||||||
|
collection = []
|
||||||
|
@repository.repository_columns
|
||||||
|
.list_type
|
||||||
|
.preload(:repository_list_items)
|
||||||
|
.each do |column|
|
||||||
|
collection << {
|
||||||
|
column_id: column.id,
|
||||||
|
list_items: column.repository_list_items
|
||||||
|
.limit(Constants::SEARCH_LIMIT)
|
||||||
|
.pluck(:id, :data)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
collection
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,6 +21,8 @@ class RepositoryColumn < ApplicationRecord
|
||||||
|
|
||||||
after_create :update_repository_table_state
|
after_create :update_repository_table_state
|
||||||
|
|
||||||
|
scope :list_type, -> { where(data_type: 'RepositoryListValue') }
|
||||||
|
|
||||||
def update_repository_table_state
|
def update_repository_table_state
|
||||||
RepositoryTableState.update_state(self, nil, created_by)
|
RepositoryTableState.update_state(self, nil, created_by)
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<th id="added-on"><%= t("repositories.table.added_on") %></th>
|
<th id="added-on"><%= t("repositories.table.added_on") %></th>
|
||||||
<th id="added-by"><%= t("repositories.table.added_by") %></th>
|
<th id="added-by"><%= t("repositories.table.added_by") %></th>
|
||||||
<% repository.repository_columns.order(:id).each do |column| %>
|
<% repository.repository_columns.order(:id).each do |column| %>
|
||||||
<th class="repository-column" id="<%= column.id %>"
|
<th class="repository-column" id="<%= column.id %>" data-type="<%= column.data_type %>"
|
||||||
<%= 'data-editable' if can_update_or_delete_repository_column?(column) %>
|
<%= 'data-editable' if can_update_or_delete_repository_column?(column) %>
|
||||||
<%= 'data-deletable' if can_update_or_delete_repository_column?(column) %>
|
<%= 'data-deletable' if can_update_or_delete_repository_column?(column) %>
|
||||||
<%= "data-edit-url='#{edit_repository_repository_column_path(repository, column)}'" %>
|
<%= "data-edit-url='#{edit_repository_repository_column_path(repository, column)}'" %>
|
||||||
|
|
|
@ -472,7 +472,6 @@ Rails.application.routes.draw do
|
||||||
as: 'columns_destroy_html'
|
as: 'columns_destroy_html'
|
||||||
|
|
||||||
resources :repository_columns, only: %i(create edit update destroy)
|
resources :repository_columns, only: %i(create edit update destroy)
|
||||||
|
|
||||||
resources :repository_rows, only: %i(create edit update)
|
resources :repository_rows, only: %i(create edit update)
|
||||||
member do
|
member do
|
||||||
post 'parse_sheet'
|
post 'parse_sheet'
|
||||||
|
@ -480,6 +479,9 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post 'repository_list_items', to: 'repository_list_items#search',
|
||||||
|
defaults: { format: 'json' }
|
||||||
|
|
||||||
get 'repository_rows/:id', to: 'repository_rows#show',
|
get 'repository_rows/:id', to: 'repository_rows#show',
|
||||||
as: :repository_row,
|
as: :repository_row,
|
||||||
defaults: { format: 'json' }
|
defaults: { format: 'json' }
|
||||||
|
|
|
@ -26,7 +26,6 @@ describe AssetTextDatum, type: :model do
|
||||||
it 'should have uniq asset' do
|
it 'should have uniq asset' do
|
||||||
create :asset_text_datum, asset: asset
|
create :asset_text_datum, asset: asset
|
||||||
new_atd = build :asset_text_datum, asset: asset
|
new_atd = build :asset_text_datum, asset: asset
|
||||||
# binding.pry
|
|
||||||
expect(new_atd).to_not be_valid
|
expect(new_atd).to_not be_valid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
21
vendor/assets/javascripts/ajax-bootstrap-select.min.js
vendored
Normal file
21
vendor/assets/javascripts/ajax-bootstrap-select.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
16
vendor/assets/stylesheets/ajax-bootstrap-select.min.css
vendored
Normal file
16
vendor/assets/stylesheets/ajax-bootstrap-select.min.css
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*!
|
||||||
|
* Ajax Bootstrap Select
|
||||||
|
*
|
||||||
|
* Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON.
|
||||||
|
*
|
||||||
|
* @version 1.4.3
|
||||||
|
* @author Adam Heim - https://github.com/truckingsim
|
||||||
|
* @link https://github.com/truckingsim/Ajax-Bootstrap-Select
|
||||||
|
* @copyright 2017 Adam Heim
|
||||||
|
* @license Released under the MIT license.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Mark Carver - https://github.com/markcarver
|
||||||
|
*
|
||||||
|
* Last build: 2017-11-15 1:19:47 PM EST
|
||||||
|
*/.bootstrap-select .status{background:#f0f0f0;clear:both;color:#999;font-size:11px;font-style:italic;font-weight:500;line-height:1;margin-bottom:-5px;padding:10px 20px}
|
Loading…
Add table
Reference in a new issue