mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-12-10 06:06:24 +08:00
Merge branch 'ux-release-1' of https://github.com/biosistemika/scinote-web into zd_SCI_2124
This commit is contained in:
commit
dafa29d4bf
52 changed files with 781 additions and 695 deletions
|
|
@ -5,7 +5,6 @@ $.fn.findWithSelf = function(selector) {
|
|||
};
|
||||
|
||||
var REPORT_CONTENT = "#report-content";
|
||||
var SIDEBAR_PARENT_TREE = "#report-sidebar-tree";
|
||||
var ADD_CONTENTS_FORM_ID = "#add-contents-form";
|
||||
var SAVE_REPORT_FORM_ID = "#save-report-form";
|
||||
|
||||
|
|
@ -31,12 +30,14 @@ var ignoreUnsavedWorkAlert;
|
|||
initializeSaveToPdf();
|
||||
initializeSaveReport();
|
||||
initializeAddContentsModal();
|
||||
initializeSidebarNavigation();
|
||||
initializeUnsavedWorkDialog();
|
||||
|
||||
$('.report-nav-link').each(function() {
|
||||
truncateLongString($(this), <%= Constants::NAME_TRUNCATION_LENGTH %>);
|
||||
});
|
||||
|
||||
// Automatically display the "Add content" modal
|
||||
$('.new-element.initial').click();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -238,9 +239,6 @@ function initializeNewElement(newEl) {
|
|||
} else if (data.status == 200) {
|
||||
// Add elements
|
||||
addElements(el, data.responseJSON.elements);
|
||||
|
||||
// Update sidebar
|
||||
initializeSidebarNavigation();
|
||||
}
|
||||
})
|
||||
.on("ajax:error", function(e, xhr, settings, error) {
|
||||
|
|
@ -486,140 +484,6 @@ function initializeUnsavedWorkDialog() {
|
|||
$(document).on('page:before-change', beforeUnload);
|
||||
}
|
||||
|
||||
/**
|
||||
* SIDEBAR CODE
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the sidebar <li> element for the specified report element.
|
||||
* @param reportEl - The .report-element in the report.
|
||||
* @return The corresponding sidebar <li>.
|
||||
*/
|
||||
function getSidebarEl(reportEl) {
|
||||
var type = reportEl.data("type");
|
||||
var scrollId = reportEl.data("scroll-id");
|
||||
return $(SIDEBAR_PARENT_TREE).find(
|
||||
"li" +
|
||||
"[data-type='" + type + "']" +
|
||||
"[data-scroll-id='" + scrollId + "']"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the report <div.report-element> element for the specified
|
||||
* sidebar element.
|
||||
* @param sidebarEl - The <li> sidebar element.
|
||||
* @return The corresponding report element.
|
||||
*/
|
||||
function getReportEl(sidebarEl) {
|
||||
var type = sidebarEl.data("type");
|
||||
var scrollId = sidebarEl.data("scroll-id");
|
||||
return $(REPORT_CONTENT).find(
|
||||
"div.report-element" +
|
||||
"[data-type='" + type + "']" +
|
||||
"[data-scroll-id='" + scrollId + "']"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the sidebar navigation pane.
|
||||
*/
|
||||
function initializeSidebarNavigation() {
|
||||
var reportContent = $(REPORT_CONTENT);
|
||||
var treeParent = $(SIDEBAR_PARENT_TREE);
|
||||
|
||||
// Remove existing contents (also remove click listeners)
|
||||
treeParent.find(".report-nav-link").off("click");
|
||||
treeParent.children().remove();
|
||||
|
||||
// Re-populate the sidebar
|
||||
_.each(reportContent.children(".report-element"), function(child) {
|
||||
var li = initSidebarElement($(child));
|
||||
li.appendTo(treeParent);
|
||||
});
|
||||
|
||||
// Add click listener on all links
|
||||
treeParent.find(".report-nav-link").click(function(e) {
|
||||
var el = $(this).closest("li");
|
||||
scrollToElement(el);
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Call to sidebar function to re-initialize tree functionality
|
||||
setupSidebarTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive call to initialize sidebar elements.
|
||||
* @param reportEl - The report element for which to
|
||||
* generate the sidebar.
|
||||
* @return A <li> jQuery element containing sidebar entry.
|
||||
*/
|
||||
function initSidebarElement(reportEl) {
|
||||
var elChildrenContainer = reportEl.children(".report-element-children");
|
||||
var type = reportEl.data("type");
|
||||
var name = reportEl.data("name");
|
||||
var scrollId = reportEl.data("scroll-id");
|
||||
var iconClass = reportEl.data("icon-class");
|
||||
|
||||
// Generate list element
|
||||
var newLi = $(document.createElement("li"));
|
||||
newLi
|
||||
.attr("data-type", type)
|
||||
.attr("data-scroll-id", scrollId);
|
||||
|
||||
var newSpan = $(document.createElement("span"));
|
||||
newSpan.appendTo(newLi);
|
||||
var newI = $(document.createElement("i"));
|
||||
newI.appendTo(newSpan);
|
||||
var newHref = $(document.createElement("a"));
|
||||
newHref
|
||||
.attr("href", "")
|
||||
.addClass("report-nav-link")
|
||||
.text(name)
|
||||
.appendTo(newSpan);
|
||||
var newIcon = $(document.createElement("span"));
|
||||
newIcon.addClass(iconClass).prependTo(newHref);
|
||||
|
||||
if (elChildrenContainer.length && elChildrenContainer.length > 0) {
|
||||
var elChildren = elChildrenContainer.children(".report-element");
|
||||
if (elChildren.length && elChildren.length > 0) {
|
||||
var newUl = $(document.createElement("ul"));
|
||||
newUl.appendTo(newLi);
|
||||
|
||||
_.each(elChildren, function(child) {
|
||||
var li = initSidebarElement($(child));
|
||||
li.appendTo(newUl);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return newLi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the specified element in the report.
|
||||
* @param sidebarEl - The sidebar element.
|
||||
*/
|
||||
function scrollToElement(sidebarEl) {
|
||||
var el = getReportEl(sidebarEl);
|
||||
|
||||
if (el.length && el.length == 1) {
|
||||
var content = $("body");
|
||||
content.scrollTo(
|
||||
el,
|
||||
{
|
||||
axis: 'y',
|
||||
duration: 500,
|
||||
offset: -150
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INDIVIDUAL ELEMENTS SORTING/MODIFYING FUNCTIONS
|
||||
*/
|
||||
|
|
@ -683,8 +547,6 @@ function sortWholeReport(asc) {
|
|||
sortElementChildren($(el), asc, true);
|
||||
});
|
||||
|
||||
// Reinitialize sidebar
|
||||
initializeSidebarNavigation();
|
||||
animateLoading(false);
|
||||
}
|
||||
|
||||
|
|
@ -734,22 +596,6 @@ function sortElementChildren(el, asc, recursive) {
|
|||
sortElementChildren($(child), asc, true);
|
||||
}
|
||||
});
|
||||
|
||||
// Update sidebar
|
||||
var prevEl = null;
|
||||
_.each(children, function(child) {
|
||||
var sidebarEl = getSidebarEl($(child));
|
||||
if (sidebarEl.length && sidebarEl.length == 1) {
|
||||
var sidebarParent = sidebarEl.closest("ul");
|
||||
sidebarEl.detach();
|
||||
if (prevEl === null) {
|
||||
sidebarParent.prepend(sidebarEl);
|
||||
} else {
|
||||
prevEl.after(sidebarEl);
|
||||
}
|
||||
prevEl = sidebarEl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -844,38 +690,24 @@ function moveElement(el, up) {
|
|||
return;
|
||||
}
|
||||
|
||||
var sidebarEl;
|
||||
if (up) {
|
||||
var prevEl = prevNewEl.prev();
|
||||
if (!prevEl.length || !prevEl.hasClass("report-element")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Move sidebar element up
|
||||
sidebarEl = getSidebarEl(el);
|
||||
var sidebarPrev = sidebarEl.prev();
|
||||
sidebarEl.detach();
|
||||
sidebarPrev.before(sidebarEl);
|
||||
|
||||
el.detach();
|
||||
nextNewEl.detach();
|
||||
prevEl.before(el);
|
||||
prevEl.before(nextNewEl);
|
||||
updateElementControls(prevEl);
|
||||
|
||||
|
||||
} else {
|
||||
var nextEl = nextNewEl.next();
|
||||
if (!nextEl.length || !nextEl.hasClass("report-element")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Move sidebar element up
|
||||
sidebarEl = getSidebarEl(el);
|
||||
var sidebarNext = sidebarEl.next();
|
||||
sidebarEl.detach();
|
||||
sidebarNext.after(sidebarEl);
|
||||
|
||||
prevNewEl.detach();
|
||||
el.detach();
|
||||
nextEl.after(el);
|
||||
|
|
@ -905,10 +737,6 @@ function removeElement(el) {
|
|||
|
||||
// TODO Remove event listeners
|
||||
|
||||
// Remove sidebar entry
|
||||
var sidebarEl = getSidebarEl(el);
|
||||
sidebarEl.remove();
|
||||
|
||||
prevNewEl.remove();
|
||||
el.remove();
|
||||
|
||||
|
|
@ -933,10 +761,6 @@ function removeResultCommentsElement(el) {
|
|||
|
||||
// TODO Remove event listeners
|
||||
|
||||
// Remove sidebar entry
|
||||
var sidebarEl = getSidebarEl(el);
|
||||
sidebarEl.remove();
|
||||
|
||||
// Remove element, show the new element container
|
||||
el.remove();
|
||||
parent.children(".new-element").removeClass("hidden");
|
||||
|
|
@ -1125,26 +949,6 @@ function constructElementContentsJson(el) {
|
|||
return jsonEl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds listeners to sidebar
|
||||
* that truncate long strings
|
||||
*/
|
||||
function initializeReportSidebartruncation() {
|
||||
var target = document.getElementById("report-sidebar-tree");
|
||||
var observer = new MutationObserver(
|
||||
function() {
|
||||
$.each($("a.report-nav-link"),
|
||||
function(){
|
||||
truncateLongString($(this),
|
||||
<%= Constants::NAME_TRUNCATION_LENGTH %>);
|
||||
});
|
||||
}
|
||||
);
|
||||
var config = { childList: true };
|
||||
|
||||
observer.observe(target, config);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Check if we are actually at new report page
|
||||
if ($(REPORT_CONTENT).length) {
|
||||
|
|
|
|||
|
|
@ -454,6 +454,10 @@ var RepositoryDatatable = (function(global) {
|
|||
$(th).attr('data-type') === 'RepositoryListValue') {
|
||||
input = initialListItemsRequest($(th).attr('id'));
|
||||
tr.appendChild(createTdElement(input));
|
||||
} else if ($(th).hasClass('repository-column') &&
|
||||
$(th).attr('data-type') === 'RepositoryAssetValue') {
|
||||
input = changeToInputFileField('repository_cell_file', th.attr('id'), '');
|
||||
tr.appendChild(createTdElement(input));
|
||||
} else {
|
||||
// Column we don't care for, just add empty td
|
||||
tr.appendChild(createTdElement(''));
|
||||
|
|
@ -566,6 +570,29 @@ var RepositoryDatatable = (function(global) {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
global.onClickCopyRepositoryRecords = function() {
|
||||
animateSpinner();
|
||||
$.ajax({
|
||||
url: $('table' + TABLE_ID).data('copy-records'),
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: { selected_rows: rowsSelected },
|
||||
success: function(data) {
|
||||
HelperModule.flashAlertMsg(data.flash, 'success');
|
||||
rowsSelected = [];
|
||||
onClickCancel();
|
||||
},
|
||||
error: function(e) {
|
||||
if (e.status === 403) {
|
||||
HelperModule.flashAlertMsg(
|
||||
I18n.t('repositories.js.permission_error'), e.responseJSON.style
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Edit record
|
||||
global.onClickEdit = function() {
|
||||
if (rowsSelected.length !== 1) {
|
||||
|
|
@ -612,19 +639,15 @@ var RepositoryDatatable = (function(global) {
|
|||
var rawIndex = TABLE.column.index('fromVisible', i);
|
||||
var colHeader = TABLE.column(rawIndex).header();
|
||||
if ($(colHeader).hasClass('repository-column')) {
|
||||
var type = $(colHeader).attr('data-type');
|
||||
// Check if cell on this record exists
|
||||
var cell = cells[$(colHeader).attr('id')];
|
||||
if (cell) {
|
||||
td.html(changeToFormField('repository_cell',
|
||||
$(colHeader).attr('id'),
|
||||
cell,
|
||||
list_columns));
|
||||
} else {
|
||||
td.html(changeToFormField('repository_cell',
|
||||
$(colHeader).attr('id'),
|
||||
'',
|
||||
list_columns));
|
||||
}
|
||||
var cell = cells[$(colHeader).attr('id')] || '';
|
||||
td.html(changeToFormField('repository_cell',
|
||||
$(colHeader).attr('id'),
|
||||
type,
|
||||
cell,
|
||||
list_columns));
|
||||
_addSelectedFile(type, cell, $(this).find('input')[0]);
|
||||
_initSelectPicker();
|
||||
}
|
||||
});
|
||||
|
|
@ -663,28 +686,32 @@ var RepositoryDatatable = (function(global) {
|
|||
node = selectedRecord;
|
||||
}
|
||||
// First fetch all the data in input fields
|
||||
var data = {
|
||||
request_url: $(TABLE_ID).data('current-uri'),
|
||||
repository_row_id: $(selectedRecord).attr('id'),
|
||||
repository_row: {},
|
||||
repository_cells: {}
|
||||
};
|
||||
var formData = new FormData();
|
||||
formData.append('request_url', $(TABLE_ID).data('current-uri'));
|
||||
formData.append('repository_row_id', $(selectedRecord).attr('id'));
|
||||
|
||||
// Direct record attributes
|
||||
// Record name
|
||||
data.repository_row.name = $('td input[data-object = repository_row]').val();
|
||||
formData.append('repository_row_name', $('td input[data-object = repository_row]').val());
|
||||
|
||||
// Custom cells text type
|
||||
$(node).find('td input[data-object = repository_cell]').each(function() {
|
||||
// Send data only and only if cell is not empty
|
||||
if ($(this).val().trim()) {
|
||||
data.repository_cells[$(this).attr('name')] = $(this).val();
|
||||
formData.append('repository_cells[' + $(this).attr('name') + ']', $(this).val());
|
||||
}
|
||||
});
|
||||
// Custom cells file type
|
||||
$(node).find('td input[data-object = repository_cell_file]').each(function() {
|
||||
// Send data only and only if cell is not empty
|
||||
if ($(this).context.files.length == 1) {
|
||||
formData.append('repository_cells[' + $(this).attr('name') + ']', $(this).context.files[0]);
|
||||
}
|
||||
});
|
||||
// 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;
|
||||
formData.append('repository_cells[' + $(el).attr('column_id') + ']', value);
|
||||
});
|
||||
|
||||
var url;
|
||||
|
|
@ -700,7 +727,9 @@ var RepositoryDatatable = (function(global) {
|
|||
url: url,
|
||||
type: type,
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function(data) {
|
||||
HelperModule.flashAlertMsg(data.flash, 'success');
|
||||
SmartAnnotation.closePopup();
|
||||
|
|
@ -769,6 +798,8 @@ var RepositoryDatatable = (function(global) {
|
|||
$('.repository-row-selector').removeClass('disabled');
|
||||
$('.repository-row-selector').prop('disabled', false);
|
||||
if (rowsSelected.length === 0) {
|
||||
$('#copyRepositoryRecords').prop('disabled', true);
|
||||
$('#copyRepositoryRecords').addClass('disabled');
|
||||
$('#editRepositoryRecord').prop('disabled', true);
|
||||
$('#editRepositoryRecord').addClass('disabled');
|
||||
$('#deleteRepositoryRecordsButton').prop('disabled', true);
|
||||
|
|
@ -806,6 +837,8 @@ var RepositoryDatatable = (function(global) {
|
|||
}
|
||||
$('#deleteRepositoryRecordsButton').prop('disabled', false);
|
||||
$('#deleteRepositoryRecordsButton').removeClass('disabled');
|
||||
$('#copyRepositoryRecords').prop('disabled', false);
|
||||
$('#copyRepositoryRecords').removeClass('disabled');
|
||||
$('#assignRepositoryRecords').removeClass('disabled');
|
||||
$('#assignRepositoryRecords').prop('disabled', false);
|
||||
$('#unassignRepositoryRecords').removeClass('disabled');
|
||||
|
|
@ -910,6 +943,15 @@ var RepositoryDatatable = (function(global) {
|
|||
return _listItemDropdown(massage_response, '-1', column_id);
|
||||
}
|
||||
|
||||
function _addSelectedFile(type, cell, input) {
|
||||
if (type === 'RepositoryAssetValue' && cell.value != null) {
|
||||
const dT = new ClipboardEvent('').clipboardData || // Firefox workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
|
||||
new DataTransfer(); // specs compliant (as of March 2018 only Chrome)
|
||||
dT.items.add(new File([_], cell.value.file_file_name));
|
||||
input.files = dT.files;
|
||||
}
|
||||
}
|
||||
|
||||
function _initSelectPicker() {
|
||||
$('.selectpicker')
|
||||
.selectpicker({liveSearch: true})
|
||||
|
|
@ -972,21 +1014,23 @@ var RepositoryDatatable = (function(global) {
|
|||
object + "' name='" + name + "' value='" + value + "'></input></div>";
|
||||
}
|
||||
|
||||
// Takes object and surrounds it with input
|
||||
function changeToInputFileField(object, name, value) {
|
||||
return "<div class='form-group'><input type='file' class='form-control' data-object='" +
|
||||
object + "' name='" + name + "' value='" + value + "'></input></div>";
|
||||
}
|
||||
|
||||
// Takes an object and creates custom html element
|
||||
function changeToFormField(object, name, cell, list_columns) {
|
||||
if (cell === '') {
|
||||
function changeToFormField(object, name, column_type, cell, list_columns) {
|
||||
var value = cell.value || '';
|
||||
if (column_type === 'RepositoryListValue') {
|
||||
var column = _.findWhere(list_columns, { column_id: parseInt(name) });
|
||||
if (column) {
|
||||
return _listItemDropdown(column.list_items, '', parseInt(name));
|
||||
} else {
|
||||
return changeToInputField(object, name, '');
|
||||
}
|
||||
var list_items = column.list_items || cell.list_items;
|
||||
return _listItemDropdown(list_items, value, parseInt(name));
|
||||
} else if (column_type === 'RepositoryAssetValue') {
|
||||
return changeToInputFileField('repository_cell_file', name, value);
|
||||
} else {
|
||||
if (cell.type === 'RepositoryListValue') {
|
||||
return _listItemDropdown(cell.list_items, cell.value, parseInt(name));
|
||||
} else {
|
||||
return changeToInputField(object, name, cell.value);
|
||||
}
|
||||
return changeToInputField(object, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -189,8 +189,16 @@
|
|||
}).on('ajax:error', function(e, xhr) {
|
||||
animateSpinner(null, false);
|
||||
if (modalID) {
|
||||
var field = { "name": xhr.responseJSON.message }
|
||||
$(form).renderFormErrors('repository_column', field, true, e);
|
||||
if(xhr.responseJSON.message.hasOwnProperty('repository_list_items')) {
|
||||
var message = xhr.responseJSON.message['repository_list_items'];
|
||||
$('.dnd-error').remove();
|
||||
$('#manageRepositoryColumn ').find('.bootstrap-tagsinput').after(
|
||||
"<i class='dnd-error'>" + message + "</i>"
|
||||
);
|
||||
} else {
|
||||
var field = { "name": xhr.responseJSON.message }
|
||||
$(form).renderFormErrors('repository_column', field, true, e);
|
||||
}
|
||||
} else {
|
||||
HelperModule.flashAlertMsg(xhr.responseJSON.message, 'danger');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
);
|
||||
$('#wrapper').css('paddingLeft', '280px');
|
||||
$('.navbar-secondary').css(
|
||||
{ 'margin-left': '-280px', 'padding-left': '280px' }
|
||||
{ 'margin-left': '-280px', 'padding-left': '295px' }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
$('#wrapper').css('paddingLeft', '0');
|
||||
$('.navbar-secondary').css({
|
||||
'margin-left': '0',
|
||||
'padding-left': '0'
|
||||
'padding-left': '15px'
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,27 +8,33 @@
|
|||
|
||||
/* New page navbar */
|
||||
.navbar-report {
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
background: $color-concrete;
|
||||
border-bottom: 4px solid $color-silver;
|
||||
background: $color-concrete !important;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
margin-bottom: 0;
|
||||
min-width: 320px;
|
||||
padding: 0 15px;
|
||||
z-index: 500;
|
||||
padding-right: 100px;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 500;
|
||||
|
||||
div.row {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#report-menu {
|
||||
margin: 15px 0;
|
||||
|
||||
form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
& > div.row {
|
||||
|
|
@ -54,43 +60,6 @@ label {
|
|||
}
|
||||
}
|
||||
|
||||
/* New page sidebar */
|
||||
.report-sidebar-wrapper {
|
||||
background-color: $color-white !important;
|
||||
}
|
||||
|
||||
// Some additional styling on the treeview
|
||||
.report-tree {
|
||||
li {
|
||||
padding: 0 0 0 15px;
|
||||
|
||||
a.report-nav-link:visited {
|
||||
text-decoration: none;
|
||||
}
|
||||
a.report-nav-link:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
[data-type='step']:not(.parent_li) {
|
||||
padding-left: 27px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.report-sidebar-panel-description {
|
||||
margin: 10px 10px 0 10px;
|
||||
}
|
||||
|
||||
.report-item-elements {
|
||||
margin-top: 10px !important;
|
||||
margin-left: 15px !important;
|
||||
|
||||
li {
|
||||
margin: 5px 5px 5px 15px;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Global fix for handsontable
|
||||
|
|
@ -115,19 +84,20 @@ label {
|
|||
.report-container {
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
padding-left: 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#report-content {
|
||||
color: $color-black;
|
||||
@include box-shadow(0 0 58px -10px $color-black);
|
||||
background: $color-white;
|
||||
@include box-shadow(0px 0px 58px -10px $color-black);
|
||||
max-width: 800px;
|
||||
min-width: 230px;
|
||||
min-height: 1200px;
|
||||
color: $color-black;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 50px;
|
||||
max-width: 800px;
|
||||
min-height: 1200px;
|
||||
min-width: 230px;
|
||||
padding: 45px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,12 @@
|
|||
padding-top: 5px;
|
||||
}
|
||||
|
||||
li:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
margin-left: 15px;
|
||||
text-align: right;
|
||||
width: 300px;
|
||||
}
|
||||
|
|
@ -348,6 +353,15 @@
|
|||
margin-left: 83px;
|
||||
}
|
||||
|
||||
#search-bar {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#search-bar {
|
||||
padding: 10px 30px;
|
||||
}
|
||||
}
|
||||
|
||||
// reset margins on small screens
|
||||
@media (max-width: 1188px) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
padding-top: 16px;
|
||||
position: fixed;
|
||||
width: 83px;
|
||||
z-index: 1001;
|
||||
|
||||
ul.nav > li {
|
||||
padding-right: 4px;
|
||||
|
|
|
|||
|
|
@ -37,3 +37,8 @@
|
|||
float: left;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.custom-alert-info {
|
||||
background-color: $brand-info;
|
||||
padding: 10px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ a[data-toggle="tooltip"] {
|
|||
|
||||
#secondary-navigation {
|
||||
white-space: nowrap;
|
||||
overflow: hidden
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
|
|
@ -253,10 +253,23 @@ a[data-toggle="tooltip"] {
|
|||
border-right: 0;
|
||||
border-bottom: 4px solid $color-silver;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.navbar-toggle {
|
||||
margin-right: 100px;
|
||||
}
|
||||
|
||||
#secondary-menu {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.nav-name {
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
ul.nav {
|
||||
margin-right: 0;
|
||||
margin-right: 60px;
|
||||
|
||||
& > li {
|
||||
text-transform: uppercase;
|
||||
|
|
@ -409,13 +422,6 @@ a[data-toggle="tooltip"] {
|
|||
}
|
||||
|
||||
/** Protocols management */
|
||||
.breadcrumb-protocols-manager {
|
||||
overflow: visible;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
background-color: $color-white;
|
||||
}
|
||||
|
||||
.tab-pane-protocols {
|
||||
& > div.protocols-description {
|
||||
margin-bottom: 15px;
|
||||
|
|
@ -1277,7 +1283,6 @@ table.dataTable {
|
|||
|
||||
.file-preview-container {
|
||||
align-items: center;
|
||||
background-color: $color-white;
|
||||
color: $gray-dark;
|
||||
display: -moz-flex;
|
||||
display: -webkit-flex;
|
||||
|
|
|
|||
|
|
@ -7,20 +7,19 @@ class ExperimentsController < ApplicationController
|
|||
include Rails.application.routes.url_helpers
|
||||
|
||||
before_action :set_experiment,
|
||||
except: [:new, :create]
|
||||
except: %i(new create)
|
||||
before_action :set_project,
|
||||
only: [:new, :create, :samples_index, :samples, :module_archive,
|
||||
:clone_modal, :move_modal, :delete_samples]
|
||||
before_action :load_projects_by_teams, only: %i(canvas samples)
|
||||
only: %i(new create samples_index samples module_archive
|
||||
clone_modal move_modal delete_samples)
|
||||
before_action :load_projects_by_teams, only: %i(canvas samples module_archive)
|
||||
before_action :check_view_permissions,
|
||||
only: [:canvas, :module_archive]
|
||||
only: %i(canvas module_archive)
|
||||
before_action :check_manage_permissions, only: :edit
|
||||
before_action :check_archive_permissions, only: :archive
|
||||
before_action :check_clone_permissions, only: %i(clone_modal clone)
|
||||
before_action :check_move_permissions, only: %i(move_modal move)
|
||||
|
||||
# except parameter could be used but it is not working.
|
||||
layout :choose_layout
|
||||
layout 'fluid'.freeze
|
||||
|
||||
# Action defined in SampleActions
|
||||
DELETE_SAMPLES = 'Delete'.freeze
|
||||
|
|
@ -350,7 +349,8 @@ class ExperimentsController < ApplicationController
|
|||
end
|
||||
|
||||
def load_projects_by_teams
|
||||
@projects_by_teams = current_user.projects_by_teams
|
||||
@projects_by_teams = current_user.projects_by_teams(current_team.id,
|
||||
nil, false)
|
||||
end
|
||||
|
||||
def check_view_permissions
|
||||
|
|
@ -373,10 +373,6 @@ class ExperimentsController < ApplicationController
|
|||
render_403 unless can_move_experiment?(@experiment)
|
||||
end
|
||||
|
||||
def choose_layout
|
||||
action_name.in?(%w(index archive)) ? 'main' : 'fluid'
|
||||
end
|
||||
|
||||
def experiment_annotation_notification(old_text = nil)
|
||||
smart_annotation_notification(
|
||||
old_text: old_text,
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ class MyModulesController < ApplicationController
|
|||
before_action :load_repository, only: %i(assign_repository_records
|
||||
unassign_repository_records
|
||||
repository_index)
|
||||
before_action :load_projects_by_teams,
|
||||
only: %i(protocols results activities samples repository)
|
||||
before_action :load_projects_by_teams, only: %i(protocols results activities
|
||||
samples repository archive)
|
||||
before_action :check_manage_permissions,
|
||||
only: %i(update destroy description due_date)
|
||||
before_action :check_view_info_permissions, only: :show
|
||||
|
|
@ -608,7 +608,8 @@ class MyModulesController < ApplicationController
|
|||
end
|
||||
|
||||
def load_projects_by_teams
|
||||
@projects_by_teams = current_user.projects_by_teams
|
||||
@projects_by_teams = current_user.projects_by_teams(current_team.id,
|
||||
nil, false)
|
||||
end
|
||||
|
||||
def check_manage_permissions
|
||||
|
|
|
|||
|
|
@ -5,19 +5,19 @@ class ProjectsController < ApplicationController
|
|||
include InputSanitizeHelper
|
||||
|
||||
before_action :generate_intro_demo, only: :index
|
||||
before_action :load_vars, only: [:show, :edit, :update,
|
||||
:notifications, :reports,
|
||||
:samples, :experiment_archive,
|
||||
:delete_samples, :samples_index]
|
||||
before_action :load_projects_by_teams, only: %i(index show samples)
|
||||
before_action :load_vars, only: %i(show edit update
|
||||
notifications reports
|
||||
samples experiment_archive
|
||||
delete_samples samples_index)
|
||||
before_action :load_projects_by_teams, only: %i(index show samples archive
|
||||
experiment_archive)
|
||||
before_action :load_archive_vars, only: :archive
|
||||
before_action :check_view_permissions, only: %i(show reports notifications
|
||||
samples experiment_archive
|
||||
samples_index)
|
||||
before_action :check_create_permissions, only: [ :new, :create ]
|
||||
before_action :check_create_permissions, only: %i(new create)
|
||||
before_action :check_manage_permissions, only: :edit
|
||||
|
||||
@filter_by_archived = false
|
||||
|
||||
# except parameter could be used but it is not working.
|
||||
layout 'fluid'
|
||||
|
||||
|
|
@ -36,7 +36,6 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
|
||||
def archive
|
||||
@filter_by_archived = true
|
||||
index
|
||||
end
|
||||
|
||||
|
|
@ -322,7 +321,16 @@ class ProjectsController < ApplicationController
|
|||
@current_sort = params[:sort].to_s
|
||||
@projects_by_teams = current_user.projects_by_teams(@current_team_id,
|
||||
@current_sort,
|
||||
@filter_by_archived)
|
||||
false)
|
||||
else
|
||||
@projects_by_teams = []
|
||||
end
|
||||
end
|
||||
|
||||
def load_archive_vars
|
||||
if current_user.teams.any?
|
||||
@archived_projects_by_teams =
|
||||
current_user.projects_by_teams(@current_team_id, @current_sort, true)
|
||||
else
|
||||
@projects_by_teams = []
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ class ReportsController < ApplicationController
|
|||
# before_action :check_view_permissions, only: :index
|
||||
before_action :check_manage_permissions, only: BEFORE_ACTION_METHODS
|
||||
|
||||
layout 'fluid'
|
||||
|
||||
# Index showing all reports of a single project
|
||||
def index; end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class RepositoriesController < ApplicationController
|
|||
before_action :check_manage_permissions, only:
|
||||
%i(destroy destroy_modal rename_modal update)
|
||||
before_action :check_create_permissions, only:
|
||||
%i(create_new_modal create copy_modal copy)
|
||||
%i(create_modal create copy_modal copy)
|
||||
|
||||
layout 'fluid'
|
||||
|
||||
|
|
|
|||
|
|
@ -28,28 +28,35 @@ class RepositoryColumnsController < ApplicationController
|
|||
@repository_column.created_by = current_user
|
||||
|
||||
respond_to do |format|
|
||||
if @repository_column.save
|
||||
generate_repository_list_items(params[:list_items])
|
||||
format.json do
|
||||
render json: {
|
||||
id: @repository_column.id,
|
||||
name: escape_input(@repository_column.name),
|
||||
message: t('libraries.repository_columns.create.success_flash',
|
||||
name: @repository_column.name),
|
||||
edit_url:
|
||||
edit_repository_repository_column_path(@repository,
|
||||
@repository_column),
|
||||
update_url:
|
||||
repository_repository_column_path(@repository,
|
||||
@repository_column),
|
||||
destroy_html_url:
|
||||
repository_columns_destroy_html_path(@repository,
|
||||
@repository_column)
|
||||
},
|
||||
status: :ok
|
||||
end
|
||||
else
|
||||
format.json do
|
||||
format.json do
|
||||
if @repository_column.save
|
||||
if generate_repository_list_items(params[:list_items])
|
||||
render json: {
|
||||
id: @repository_column.id,
|
||||
name: escape_input(@repository_column.name),
|
||||
message: t('libraries.repository_columns.create.success_flash',
|
||||
name: @repository_column.name),
|
||||
edit_url:
|
||||
edit_repository_repository_column_path(@repository,
|
||||
@repository_column),
|
||||
update_url:
|
||||
repository_repository_column_path(@repository,
|
||||
@repository_column),
|
||||
destroy_html_url:
|
||||
repository_columns_destroy_html_path(@repository,
|
||||
@repository_column)
|
||||
},
|
||||
status: :ok
|
||||
else
|
||||
render json: {
|
||||
message: {
|
||||
repository_list_items:
|
||||
t('libraries.repository_columns.repository_list_items_limit',
|
||||
limit: Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN)
|
||||
}
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
render json: { message: @repository_column.errors.full_messages },
|
||||
status: :unprocessable_entity
|
||||
end
|
||||
|
|
@ -74,13 +81,22 @@ class RepositoryColumnsController < ApplicationController
|
|||
format.json do
|
||||
@repository_column.update_attributes(repository_column_params)
|
||||
if @repository_column.save
|
||||
update_repository_list_items(params[:list_items])
|
||||
render json: {
|
||||
id: @repository_column.id,
|
||||
name: escape_input(@repository_column.name),
|
||||
message: t('libraries.repository_columns.update.success_flash',
|
||||
name: @repository_column.name)
|
||||
}, status: :ok
|
||||
if update_repository_list_items(params[:list_items])
|
||||
render json: {
|
||||
id: @repository_column.id,
|
||||
name: escape_input(@repository_column.name),
|
||||
message: t('libraries.repository_columns.update.success_flash',
|
||||
name: @repository_column.name)
|
||||
}, status: :ok
|
||||
else
|
||||
render json: {
|
||||
message: {
|
||||
repository_list_items:
|
||||
t('libraries.repository_columns.repository_list_items_limit',
|
||||
limit: Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN)
|
||||
}
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
render json: { message: @repository_column.errors.full_messages },
|
||||
status: :unprocessable_entity
|
||||
|
|
@ -162,7 +178,13 @@ class RepositoryColumnsController < ApplicationController
|
|||
|
||||
def generate_repository_list_items(item_names)
|
||||
return unless @repository_column.data_type == 'RepositoryListValue'
|
||||
column_items = @repository_column.repository_list_items.size
|
||||
success = true
|
||||
item_names.split(',').uniq.each do |name|
|
||||
if column_items >= Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN
|
||||
success = false
|
||||
next
|
||||
end
|
||||
RepositoryListItem.create(
|
||||
repository: @repository,
|
||||
repository_column: @repository_column,
|
||||
|
|
@ -170,11 +192,14 @@ class RepositoryColumnsController < ApplicationController
|
|||
created_by: current_user,
|
||||
last_modified_by: current_user
|
||||
)
|
||||
column_items += 1
|
||||
end
|
||||
success
|
||||
end
|
||||
|
||||
def update_repository_list_items(item_names)
|
||||
return unless @repository_column.data_type == 'RepositoryListValue'
|
||||
column_items = @repository_column.repository_list_items.size
|
||||
items_list = item_names.split(',').uniq
|
||||
existing = @repository_column.repository_list_items.pluck(:data)
|
||||
existing.each do |name|
|
||||
|
|
@ -189,8 +214,13 @@ class RepositoryColumnsController < ApplicationController
|
|||
list_item_id
|
||||
).destroy_all
|
||||
end
|
||||
success = true
|
||||
items_list.each do |name|
|
||||
next if @repository_column.repository_list_items.find_by_data(name)
|
||||
if column_items >= Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN
|
||||
success = false
|
||||
next
|
||||
end
|
||||
RepositoryListItem.create(
|
||||
repository: @repository,
|
||||
repository_column: @repository_column,
|
||||
|
|
@ -198,6 +228,8 @@ class RepositoryColumnsController < ApplicationController
|
|||
created_by: current_user,
|
||||
last_modified_by: current_user
|
||||
)
|
||||
column_items += 1
|
||||
end
|
||||
success
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ 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 index)
|
||||
before_action :load_repository,
|
||||
only: %i(create delete_records index copy_records)
|
||||
before_action :check_create_permissions, only: :create
|
||||
before_action :check_manage_permissions, only: %i(edit update delete_records)
|
||||
before_action :check_manage_permissions,
|
||||
only: %i(edit update delete_records copy_records)
|
||||
|
||||
def index
|
||||
@draw = params[:draw].to_i
|
||||
|
|
@ -30,45 +32,11 @@ class RepositoryRowsController < ApplicationController
|
|||
repository_cells: [] }
|
||||
|
||||
record.transaction do
|
||||
record.name = record_params[:name] unless record_params[:name].blank?
|
||||
record.name = record_params[:repository_row_name] unless record_params[:repository_row_name].blank?
|
||||
errors[:default_fields] = record.errors.messages unless record.save
|
||||
if cell_params
|
||||
cell_params.each do |key, value|
|
||||
column = @repository.repository_columns.detect do |c|
|
||||
c.id == key.to_i
|
||||
end
|
||||
if column.data_type == 'RepositoryListValue'
|
||||
next if value == '-1'
|
||||
# check if item existx else revert the transaction
|
||||
list_item = RepositoryListItem.where(repository_column: column)
|
||||
.find(value)
|
||||
cell_value = RepositoryListValue.new(
|
||||
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
|
||||
record_annotation_notification(record, cell_value.repository_cell)
|
||||
else
|
||||
errors[:repository_cells] << {
|
||||
"#{column.id}": cell_value.errors.messages
|
||||
}
|
||||
end
|
||||
next if create_cell_value(record, key, value, errors).nil?
|
||||
end
|
||||
end
|
||||
raise ActiveRecord::Rollback if errors[:repository_cells].any?
|
||||
|
|
@ -113,9 +81,15 @@ class RepositoryRowsController < ApplicationController
|
|||
|
||||
# Add custom cells ids as key (easier lookup on js side)
|
||||
@record.repository_cells.each do |cell|
|
||||
if cell.value_type == 'RepositoryAssetValue'
|
||||
cell_value = cell.value.asset if cell.value_type == 'RepositoryAssetValue'
|
||||
else
|
||||
cell_value = escape_input(cell.value.data)
|
||||
end
|
||||
|
||||
json[:repository_row][:repository_cells][cell.repository_column_id] = {
|
||||
repository_cell_id: cell.id,
|
||||
value: escape_input(cell.value.data),
|
||||
value: cell_value,
|
||||
type: cell.value_type,
|
||||
list_items: fetch_list_items(cell)
|
||||
}
|
||||
|
|
@ -134,7 +108,7 @@ class RepositoryRowsController < ApplicationController
|
|||
}
|
||||
|
||||
@record.transaction do
|
||||
@record.name = record_params[:name].blank? ? nil : record_params[:name]
|
||||
@record.name = record_params[:repository_row_name].blank? ? nil : record_params[:repository_row_name]
|
||||
errors[:default_fields] = @record.errors.messages unless @record.save
|
||||
if cell_params
|
||||
cell_params.each do |key, value|
|
||||
|
|
@ -154,6 +128,16 @@ class RepositoryRowsController < ApplicationController
|
|||
else
|
||||
existing.delete
|
||||
end
|
||||
elsif existing.value_type == 'RepositoryAssetValue'
|
||||
if existing.value.asset.update(file: value)
|
||||
existing.value.asset.created_by = current_user
|
||||
existing.value.asset.last_modified_by = current_user
|
||||
existing.value.asset.post_process_file(current_team)
|
||||
else
|
||||
errors[:repository_cells] << {
|
||||
"#{existing.repository_column_id}": { data: existing.value.asset.errors.messages[:file].first }
|
||||
}
|
||||
end
|
||||
else
|
||||
existing.value.data = value
|
||||
if existing.value.save
|
||||
|
|
@ -168,42 +152,7 @@ class RepositoryRowsController < ApplicationController
|
|||
else
|
||||
# Looks like it is a new cell, so we need to create new value, cell
|
||||
# will be created automatically
|
||||
column = @repository.repository_columns.detect do |c|
|
||||
c.id == key.to_i
|
||||
end
|
||||
if column.data_type == 'RepositoryListValue'
|
||||
next if value == '-1'
|
||||
# check if item existx else revert the transaction
|
||||
list_item = RepositoryListItem.where(repository_column: column)
|
||||
.find(value)
|
||||
cell_value = RepositoryListValue.new(
|
||||
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
|
||||
record_annotation_notification(@record,
|
||||
cell_value.repository_cell)
|
||||
else
|
||||
errors[:repository_cells] << {
|
||||
"#{column.id}": cell_value.errors.messages
|
||||
}
|
||||
end
|
||||
next if create_cell_value(@record, key, value, errors).nil?
|
||||
end
|
||||
end
|
||||
# Clean up empty cells, not present in updated record
|
||||
|
|
@ -240,6 +189,66 @@ class RepositoryRowsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def create_cell_value(record, key, value, errors)
|
||||
column = @repository.repository_columns.detect do |c|
|
||||
c.id == key.to_i
|
||||
end
|
||||
if column.data_type == 'RepositoryListValue'
|
||||
return if value == '-1'
|
||||
# check if item existx else revert the transaction
|
||||
list_item = RepositoryListItem.where(repository_column: column)
|
||||
.find(value)
|
||||
cell_value = RepositoryListValue.new(
|
||||
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
|
||||
}
|
||||
)
|
||||
elsif column.data_type == 'RepositoryAssetValue'
|
||||
asset = Asset.new(file: value,
|
||||
created_by: current_user,
|
||||
last_modified_by: current_user,
|
||||
team: current_team)
|
||||
if asset.save
|
||||
asset.post_process_file(current_team)
|
||||
else
|
||||
errors[:repository_cells] << {
|
||||
"#{column.id}": { data: asset.errors.messages[:file].first }
|
||||
}
|
||||
end
|
||||
cell_value = RepositoryAssetValue.new(
|
||||
asset: asset,
|
||||
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
|
||||
record_annotation_notification(record,
|
||||
cell_value.repository_cell)
|
||||
else
|
||||
errors[:repository_cells] << {
|
||||
"#{column.id}": cell_value.errors.messages
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def delete_records
|
||||
deleted_count = 0
|
||||
if selected_params
|
||||
|
|
@ -276,6 +285,17 @@ class RepositoryRowsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def copy_records
|
||||
duplicate_service = RepositoryActions::DuplicateRows.new(
|
||||
current_user, @repository, params[:selected_rows]
|
||||
)
|
||||
duplicate_service.call
|
||||
render json: {
|
||||
flash: t('repositories.copy_records_report',
|
||||
number: duplicate_service.number_of_duplicated_items)
|
||||
}, status: :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_info_modal_vars
|
||||
|
|
@ -313,7 +333,7 @@ class RepositoryRowsController < ApplicationController
|
|||
end
|
||||
|
||||
def record_params
|
||||
params.require(:repository_row).permit(:name).to_h
|
||||
params.permit(:repository_row_name).to_h
|
||||
end
|
||||
|
||||
def cell_params
|
||||
|
|
|
|||
|
|
@ -9,10 +9,14 @@ module FileIconsHelper
|
|||
file_ext = asset.file_file_name.split('.').last
|
||||
if %w(doc docm docx dot dotm dotx odt rtf).include?(file_ext)
|
||||
fa_class = 'fa-file-word'
|
||||
elsif %w(csv ods xls xlsb xlsm xlsx).include?(file_ext)
|
||||
elsif %w(ods xls xlsb xlsm xlsx).include?(file_ext)
|
||||
fa_class = 'fa-file-excel'
|
||||
elsif %w(odp pot potm potx pps ppsm ppsx ppt pptm pptx).include?(file_ext)
|
||||
fa_class = 'fa-file-powerpoint'
|
||||
elsif %w(pdf).include?(file_ext)
|
||||
fa_class = 'fa-file-pdf'
|
||||
elsif %w(txt csv tab tex).include?(file_ext)
|
||||
fa_class = 'fa-file-alt'
|
||||
end
|
||||
|
||||
# Now check for custom mappings or possible overrides
|
||||
|
|
|
|||
|
|
@ -58,4 +58,11 @@ module RepositoryDatatableHelper
|
|||
"<span class='circle disabled'> </span>"
|
||||
end
|
||||
end
|
||||
|
||||
def can_perform_repository_actions(repository)
|
||||
team = repository.team
|
||||
can_manage_repository?(repository) ||
|
||||
can_create_repositories?(team) ||
|
||||
can_manage_repository_rows?(team)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -55,4 +55,14 @@ module SecondaryNavigationHelper
|
|||
def is_module_archive?
|
||||
action_name == 'archive'
|
||||
end
|
||||
|
||||
def title_element
|
||||
if project_page?
|
||||
@project
|
||||
elsif experiment_page?
|
||||
@experiment
|
||||
elsif module_page?
|
||||
@my_module
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
110
app/services/repository_actions/duplicate_cell.rb
Normal file
110
app/services/repository_actions/duplicate_cell.rb
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module RepositoryActions
|
||||
class DuplicateCell
|
||||
def initialize(cell, new_row, user, team)
|
||||
@cell = cell
|
||||
@new_row = new_row
|
||||
@user = user
|
||||
@team = team
|
||||
end
|
||||
|
||||
def call
|
||||
self.send("duplicate_#{@cell.value_type.underscore}")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def duplicate_repository_list_value
|
||||
old_value = @cell.value
|
||||
RepositoryListValue.create(
|
||||
old_value.attributes.merge(
|
||||
id: nil, created_by: @user, last_modified_by: @user,
|
||||
repository_cell_attributes: {
|
||||
repository_row: @new_row,
|
||||
repository_column: @cell.repository_column
|
||||
}
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def duplicate_repository_text_value
|
||||
old_value = @cell.value
|
||||
RepositoryTextValue.create(
|
||||
old_value.attributes.merge(
|
||||
id: nil, created_by: @user, last_modified_by: @user,
|
||||
repository_cell_attributes: {
|
||||
repository_row: @new_row,
|
||||
repository_column: @cell.repository_column
|
||||
}
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def duplicate_repository_asset_value
|
||||
old_value = @cell.value
|
||||
new_asset = create_new_asset(old_value.asset)
|
||||
RepositoryAssetValue.create(
|
||||
old_value.attributes.merge(
|
||||
id: nil, asset: new_asset, created_by: @user, last_modified_by: @user,
|
||||
repository_cell_attributes: {
|
||||
repository_row: @new_row,
|
||||
repository_column: @cell.repository_column
|
||||
}
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def duplicate_repository_date_value
|
||||
old_value = @cell.value
|
||||
RepositoryDateValue.create(
|
||||
old_value.attributes.merge(
|
||||
id: nil, created_by: @user, last_modified_by: @user,
|
||||
repository_cell_attributes: {
|
||||
repository_row: @new_row,
|
||||
repository_column: @cell.repository_column
|
||||
}
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
# reuses the same code we have in copy protocols action
|
||||
def create_new_asset(old_asset)
|
||||
new_asset = Asset.new_empty(
|
||||
old_asset.file_file_name,
|
||||
old_asset.file_file_size
|
||||
)
|
||||
new_asset.created_by = old_asset.created_by
|
||||
new_asset.team = @team
|
||||
new_asset.last_modified_by = @user
|
||||
new_asset.file_processing = true if old_asset.is_image?
|
||||
new_asset.file = old_asset.file
|
||||
new_asset.save
|
||||
|
||||
return unless new_asset.valid?
|
||||
|
||||
if new_asset.is_image?
|
||||
new_asset.file.reprocess!(:large)
|
||||
new_asset.file.reprocess!(:medium)
|
||||
end
|
||||
|
||||
# Clone extracted text data if it exists
|
||||
if old_asset.asset_text_datum
|
||||
AssetTextDatum.create(data: new_asset.data, asset: new_asset)
|
||||
end
|
||||
|
||||
# Update estimated size of cloned asset
|
||||
# (& file_present flag)
|
||||
new_asset.update(
|
||||
estimated_size: old_asset.estimated_size,
|
||||
file_present: true
|
||||
)
|
||||
|
||||
# Update team's space taken
|
||||
@team.reload
|
||||
@team.take_space(new_asset.estimated_size)
|
||||
@team.save!
|
||||
new_asset
|
||||
end
|
||||
end
|
||||
end
|
||||
56
app/services/repository_actions/duplicate_rows.rb
Normal file
56
app/services/repository_actions/duplicate_rows.rb
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'repository_actions/duplicate_cell'
|
||||
|
||||
module RepositoryActions
|
||||
class DuplicateRows
|
||||
attr_reader :number_of_duplicated_items
|
||||
def initialize(user, repository, rows_ids = [])
|
||||
@user = user
|
||||
@repository = repository
|
||||
@rows_to_duplicate = sanitize_rows_to_duplicate(rows_ids)
|
||||
@number_of_duplicated_items = 0
|
||||
end
|
||||
|
||||
def call
|
||||
@rows_to_duplicate.each do |row_id|
|
||||
duplicate_row(row_id)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sanitize_rows_to_duplicate(rows_ids)
|
||||
process_ids = rows_ids.map(&:to_i).uniq
|
||||
@repository.repository_rows.where(id: process_ids).pluck(:id)
|
||||
end
|
||||
|
||||
def duplicate_row(id)
|
||||
row = RepositoryRow.find_by_id(id)
|
||||
new_row = RepositoryRow.new(
|
||||
row.attributes.merge(new_row_attributes(row.name))
|
||||
)
|
||||
|
||||
if new_row.save
|
||||
@number_of_duplicated_items += 1
|
||||
row.repository_cells.each do |cell|
|
||||
duplicate_repository_cell(cell, new_row)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def new_row_attributes(name)
|
||||
timestamp = DateTime.now
|
||||
{ id: nil,
|
||||
name: "#{name} (1)",
|
||||
created_at: timestamp,
|
||||
updated_at: timestamp }
|
||||
end
|
||||
|
||||
def duplicate_repository_cell(cell, new_row)
|
||||
RepositoryActions::DuplicateCell.new(
|
||||
cell, new_row, @user, @repository.team
|
||||
).call
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -56,7 +56,7 @@ module SmartAnnotations
|
|||
end
|
||||
|
||||
def trim_repository_name(name)
|
||||
name.strip.slice(0..2).upcase
|
||||
name.strip.slice(0..2).capitalize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ module RepositoryImportParser
|
|||
|
||||
def import_rows!
|
||||
errors = false
|
||||
column_items = []
|
||||
@rows.each do |row|
|
||||
# Skip empty rows
|
||||
next if row.empty?
|
||||
|
|
@ -71,16 +72,28 @@ module RepositoryImportParser
|
|||
end
|
||||
|
||||
row_cell_values = []
|
||||
|
||||
row.each.with_index do |value, index|
|
||||
column = @columns[index]
|
||||
size = 0
|
||||
if column && value.present?
|
||||
if column.data_type == 'RepositoryListValue'
|
||||
current_items_column = get_items_column(column_items, column)
|
||||
size = current_items_column.list_items_number
|
||||
end
|
||||
# uses RepositoryCellValueResolver to retrieve the correct value
|
||||
cell_value_resolver =
|
||||
RepositoryImportParser::RepositoryCellValueResolver.new(
|
||||
column, @user, @repository
|
||||
column,
|
||||
@user,
|
||||
@repository,
|
||||
size
|
||||
)
|
||||
cell_value = cell_value_resolver.get_value(value, record_row)
|
||||
if column.data_type == 'RepositoryListValue'
|
||||
current_items_column.list_items_number =
|
||||
cell_value_resolver.column_list_items_size
|
||||
end
|
||||
next if cell_value.nil? # checks the case if we reach items limit
|
||||
unless cell_value.valid?
|
||||
errors = true
|
||||
raise ActiveRecord::Rollback
|
||||
|
|
@ -125,5 +138,21 @@ module RepositoryImportParser
|
|||
).failed_instances.any?
|
||||
true
|
||||
end
|
||||
|
||||
def get_items_column(list, column)
|
||||
current_column = nil
|
||||
list.each do |element|
|
||||
current_column = element if element.has_column? column
|
||||
end
|
||||
unless current_column
|
||||
new_column = RepositoryImportParser::ListItemsColumn.new(
|
||||
column,
|
||||
column.repository_list_items.size
|
||||
)
|
||||
list << new_column
|
||||
return new_column
|
||||
end
|
||||
current_column
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
14
app/utilities/repository_import_parser/list_items_column.rb
Normal file
14
app/utilities/repository_import_parser/list_items_column.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
module RepositoryImportParser
|
||||
class ListItemsColumn
|
||||
attr_accessor :column, :list_items_number
|
||||
|
||||
def initialize(column, list_items_number)
|
||||
@column = column
|
||||
@list_items_number = list_items_number
|
||||
end
|
||||
|
||||
def has_column?(column)
|
||||
@column == column
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -4,10 +4,12 @@
|
|||
# it to the repository_row
|
||||
module RepositoryImportParser
|
||||
class RepositoryCellValueResolver
|
||||
def initialize(column, user, repository)
|
||||
attr_reader :column_list_items_size
|
||||
def initialize(column, user, repository, size)
|
||||
@column = column
|
||||
@user = user
|
||||
@repository = repository
|
||||
@column_list_items_size = size
|
||||
end
|
||||
|
||||
def get_value(value, record_row)
|
||||
|
|
@ -30,6 +32,7 @@ module RepositoryImportParser
|
|||
def new_repository_list_value(value, record_row)
|
||||
list_item = @column.repository_list_items.find_by_data(value)
|
||||
list_item ||= create_repository_list_item(value)
|
||||
return unless list_item
|
||||
RepositoryListValue.new(
|
||||
created_by: @user,
|
||||
last_modified_by: @user,
|
||||
|
|
@ -42,13 +45,18 @@ module RepositoryImportParser
|
|||
end
|
||||
|
||||
def create_repository_list_item(value)
|
||||
RepositoryListItem.create(
|
||||
data: value,
|
||||
created_by: @user,
|
||||
last_modified_by: @user,
|
||||
repository_column: @column,
|
||||
repository: @repository
|
||||
)
|
||||
if @column_list_items_size >= Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN
|
||||
return
|
||||
end
|
||||
item = RepositoryListItem.new(data: value,
|
||||
created_by: @user,
|
||||
last_modified_by: @user,
|
||||
repository_column: @column,
|
||||
repository: @repository)
|
||||
if item.save
|
||||
@column_list_items_size += 1
|
||||
return item
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@
|
|||
<div class="col-xs-3">
|
||||
<% i = 0 %>
|
||||
<% @archived_results.each do |result| %>
|
||||
|
||||
<%= render partial: "my_modules/archive/result.html.erb", locals: { result: result } %>
|
||||
|
||||
<% i = i + 1 %>
|
||||
<% end %>
|
||||
|
||||
<% if i == 0 %>
|
||||
<em><%=t "my_modules.module_archive.no_archived_results" %></em>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>window.initPreviewModal()</script>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@
|
|||
<li>
|
||||
<% option_text = t("my_modules.module_archive.option_download") %>
|
||||
<% if result.is_asset %>
|
||||
<%= link_to option_text, download_asset_path(result.asset), data: {no_turbolink: true} %>
|
||||
<%= link_to t('protocols.index.archive_results.preview'), download_asset_path(result.asset),
|
||||
class: 'file-preview-link',
|
||||
id: "modal_link#{result.asset.id}",
|
||||
data: { no_turbolink: true, id: true, status: 'asset-present', 'preview-url': asset_file_preview_path(result.asset) } %>
|
||||
<% elsif result.is_text %>
|
||||
<%= link_to option_text, result_text_download_path(result.result_text_id), data: {no_turbolink: true} %>
|
||||
<% elsif result.is_table %>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<% provide(:head_title, t("projects.archive.head_title")) %>
|
||||
<%= render partial: "shared/sidebar" %>
|
||||
|
||||
<% if @projects_by_teams.length > 0 %>
|
||||
<% if @archived_projects_by_teams.length > 0 %>
|
||||
<div id="projects-toolbar">
|
||||
|
||||
<form class="form-inline" action="<%= projects_archive_path %>">
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
</form>
|
||||
</div>
|
||||
|
||||
<% @projects_by_teams.each do |team, projects| %>
|
||||
<% @archived_projects_by_teams.each do |team, projects| %>
|
||||
<%= render partial: 'projects/archive/team_projects',
|
||||
locals: {team: team, projects: projects} %>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
<ol class="breadcrumb breadcrumb-protocols-manager">
|
||||
<% if action_name == "index" %>
|
||||
<li><%= link_to current_team.name, projects_path(team: current_team) %></li>
|
||||
<li class="active"><%= t("protocols.nav.breadcrumbs.manager") %></li>
|
||||
<% else %>
|
||||
<li><%= link_to current_team.name, projects_path(team: current_team) %></li>
|
||||
<li><%= link_to t("protocols.nav.breadcrumbs.manager"), protocols_path(team: current_team, type: type) %></li>
|
||||
<% end %>
|
||||
<% if action_name == "edit" %>
|
||||
<li class="active">
|
||||
<%= t("protocols.nav.breadcrumbs.edit") %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ol>
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
<% provide(:head_title, t("protocols.edit.head_title")) %>
|
||||
|
||||
<%= render partial: 'shared/drag_n_drop_overlay' %>
|
||||
<%= render partial: "protocols/breadcrumbs.html.erb",
|
||||
locals: { teams: @teams,
|
||||
current_team: @protocol.team,
|
||||
type: @type } %>
|
||||
|
||||
<%= render partial: "protocols/header.html.erb" %>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
<% provide(:head_title, t("protocols.index.head_title")) %>
|
||||
|
||||
<% if current_team %>
|
||||
<%= render partial: "protocols/breadcrumbs.html.erb", locals: { teams: @teams, current_team: @current_team, type: @type } %>
|
||||
<ul class="nav nav-tabs nav-settings">
|
||||
<li role="presentation" class="<%= "active" if @type == :public %>">
|
||||
<%= link_to t("protocols.index.navigation.public"), protocols_path(team: @current_team, type: :public) %>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
<% provide(:head_title, t("projects.reports.new.head_title", project: h(@project.name)).html_safe) %>
|
||||
<% provide(:body_class, "report-body") %>
|
||||
<% provide(:sidebar_wrapper_class, "report-sidebar-wrapper") %>
|
||||
<% provide(:container_class, "report-container") %>
|
||||
|
||||
<%= render partial: "reports/new/report_sidebar" %>
|
||||
<%= render partial: "reports/new/report_navigation" %>
|
||||
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,65 +1,37 @@
|
|||
<% content_for :secondary_navigation do %>
|
||||
|
||||
<div class="navbar-report">
|
||||
<div>
|
||||
<ul class="breadcrumb" style="margin-left: 15px;">
|
||||
<li>
|
||||
<% if can_read_team?(@project.team) %>
|
||||
<a id="team-link"
|
||||
href="<%= projects_path :team => @project.team.id %>">
|
||||
<% end %>
|
||||
<span class="hidden-sm hidden-md hidden-lg">Org</span>
|
||||
<span class="hidden-xs"><%= @project.team.name %></span>
|
||||
<% if can_read_team?(@project.team) %>
|
||||
</a>
|
||||
<% end %>
|
||||
</li>
|
||||
<li class="active">
|
||||
<span class="hidden-sm hidden-md hidden-lg">Project</span>
|
||||
<span class="hidden-xs"><%= @project.name %></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="center-block" id="report-menu">
|
||||
|
||||
<div class="dropdown" id="sort-report">
|
||||
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<span class="glyphicon glyphicon-sort visible-xs-inline"></span>
|
||||
<span class="hidden-xs"><%= t'projects.reports.new.nav_sort_by' %></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="#" data-sort="desc"><%= t('projects.reports.new.nav_sort_desc') %></a></li>
|
||||
<li><a href="#" data-sort="asc"><%= t('projects.reports.new.nav_sort_asc') %></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<%= link_to "", class: "btn btn-primary", remote: true, id: "print-report" do %>
|
||||
<span class="glyphicon glyphicon-print"></span>
|
||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_print" %></span>
|
||||
<% end %>
|
||||
<%= form_tag generate_project_reports_path(@project, format: :pdf), method: :post, target: "_blank", class: "get-report-pdf-form" do %>
|
||||
<div class="form-group">
|
||||
<%= hidden_field_tag "html", "" %>
|
||||
<%= link_to "", class: "btn btn-primary", remote: true, id: "get-report-pdf" do %>
|
||||
<span class="glyphicon glyphicon-save-file"></span>
|
||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_pdf" %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= link_to "", class: "btn btn-primary", remote: true, id: "save-report-link" do %>
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_save" %></span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to project_reports_path(@project), id: "cancel-report-link", class: "btn btn-default" do %>
|
||||
<span class="glyphicon glyphicon-remove"></span>
|
||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_close" %></span>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
<div class="navbar-report">
|
||||
<div class="center-block" id="report-menu">
|
||||
|
||||
<div class="dropdown" id="sort-report">
|
||||
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<span class="glyphicon glyphicon-sort visible-xs-inline"></span>
|
||||
<span class="hidden-xs"><%= t'projects.reports.new.nav_sort_by' %></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a href="#" data-sort="desc"><%= t('projects.reports.new.nav_sort_desc') %></a></li>
|
||||
<li><a href="#" data-sort="asc"><%= t('projects.reports.new.nav_sort_asc') %></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= link_to "", class: "btn btn-primary", remote: true, id: "print-report" do %>
|
||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_print" %></span>
|
||||
<% end %>
|
||||
<%= form_tag generate_project_reports_path(@project, format: :pdf), method: :post, target: "_blank", class: "get-report-pdf-form" do %>
|
||||
<div class="form-group">
|
||||
<%= hidden_field_tag "html", "" %>
|
||||
<%= link_to "", class: "btn btn-primary", remote: true, id: "get-report-pdf" do %>
|
||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_pdf" %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= link_to "", class: "btn btn-primary", remote: true, id: "save-report-link" do %>
|
||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_save" %></span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to project_reports_path(@project), id: "cancel-report-link", class: "btn btn-default pull-right" do %>
|
||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_close" %></span>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
<ol class="breadcrumb breadcrumb-protocols-manager">
|
||||
<li><%= link_to current_team.name, projects_path(team: current_team) %></li>
|
||||
<li class="active"><%= t("repositories.nav.breadcrumbs.repositories") %></li>
|
||||
</ol>
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<div><%=t('zip_export.repository_header_html', repository: repository.name) %></div>
|
||||
<div class="alert alert-info" role="alert"><%=t 'zip_export.files_alert' %></div>
|
||||
<div class="custom-alert-info"><%=t 'zip_export.files_alert' %></div>
|
||||
<div><%=t 'zip_export.repository_footer_html' %></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@
|
|||
</div>
|
||||
<div class="alert alert-info" role="alert">
|
||||
<ul>
|
||||
<li><%= t('repositories.modal_parse.warning_1') %></li>
|
||||
<li><%= t('repositories.modal_parse.warning_2') %></li>
|
||||
<li><%=t 'repositories.modal_parse.warning_1', limit: Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN %></li>
|
||||
<li><%=t 'repositories.modal_parse.warning_2' %></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
data-num-columns="<%= 6 + repository.repository_columns.count %>"
|
||||
data-create-record="<%= repository_repository_rows_path(repository) %>"
|
||||
data-delete-record="<%= repository_delete_records_path(repository) %>"
|
||||
data-copy-records="<%= repository_copy_records_path(repository) %>"
|
||||
data-max-dropdown-length="<%= Constants::NAME_TRUNCATION_LENGTH_DROPDOWN %>"
|
||||
data-save-text="<%= I18n.t('general.save') %>"
|
||||
data-edit-text="<%= I18n.t('general.edit') %>"
|
||||
|
|
|
|||
|
|
@ -6,15 +6,19 @@
|
|||
# show only if no repositories present. If the team will have them we will
|
||||
# handle this in left side navigation bar
|
||||
%>
|
||||
<div class="jumbotron text-center" style="margin-top:25%">
|
||||
<div class="jumbotron text-center" style="margin-top:18%">
|
||||
<strong><%=t 'libraries.index.no_libraries.text' %></strong>
|
||||
<h2><strong><%=t 'libraries.index.no_libraries.title' %><strong></h2>
|
||||
<br />
|
||||
<%= link_to t('libraries.index.no_libraries.create_new_button'),
|
||||
create_modal_team_repositories_path(current_team),
|
||||
class: "btn btn-primary btn-lg",
|
||||
id: "create-new-repository",
|
||||
remote: true %>
|
||||
<% if can_create_repositories?(current_team) %>
|
||||
<h2><strong><%=t 'libraries.index.no_libraries.title' %><strong></h2>
|
||||
<br />
|
||||
<%= link_to t('libraries.index.no_libraries.create_new_button'),
|
||||
create_modal_team_repositories_path(current_team),
|
||||
class: "btn btn-primary btn-lg",
|
||||
id: "create-new-repository",
|
||||
remote: true %>
|
||||
<% else %>
|
||||
<h2><strong><%=t 'libraries.index.no_libraries.no_permission_title' %><strong></h2>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<!-- If member of no teams -->
|
||||
|
|
|
|||
|
|
@ -20,11 +20,12 @@
|
|||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="true"
|
||||
<%= "disabled" unless can_manage_repository?(@repository) || can_create_repositories?(@repository.team) %>>
|
||||
<%= "disabled" unless can_perform_repository_actions(@repository) %>>
|
||||
<span class="glyphicon glyphicon-cog"></span>
|
||||
<span class="caret"></span>
|
||||
</div>
|
||||
<% if can_manage_repository?(@repository) || can_create_repositories?(@repository.team) %>
|
||||
|
||||
<% if can_perform_repository_actions(@repository) %>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
<li class="dropdown-header">
|
||||
<%= t("repositories.index.options_dropdown.header") %>
|
||||
|
|
@ -36,6 +37,8 @@
|
|||
class: "rename-repo-option",
|
||||
remote: true %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if can_create_repository_columns?(@repository.team) %>
|
||||
<li>
|
||||
<%= link_to t('repositories.index.options_dropdown.manage_columns'),
|
||||
repository_repository_columns_path(@repository) %>
|
||||
|
|
@ -105,12 +108,11 @@
|
|||
|
||||
<!-- These buttons are appended to table in javascript, after table initialization -->
|
||||
<div class="toolbarButtons" style="display:none">
|
||||
<button type="button" class="btn btn-default editAdd" id="editRepositoryRecord" onclick="onClickEdit()" disabled>
|
||||
<span class="glyphicon glyphicon-pencil"></span>
|
||||
<span class="hidden-xs-custom"><%= t("repositories.edit_record") %></span>
|
||||
</button>
|
||||
|
||||
<% if can_manage_repository_rows?(@repository.team) %>
|
||||
<button type="button" class="btn btn-default editAdd" id="editRepositoryRecord" onclick="onClickEdit()" disabled>
|
||||
<span class="glyphicon glyphicon-pencil"></span>
|
||||
<span class="hidden-xs-custom"><%= t("repositories.edit_record") %></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
id="deleteRepositoryRecordsButton" data-target="#deleteRepositoryRecord" data-toggle="modal" disabled>
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
|
|
@ -118,6 +120,10 @@
|
|||
<%= submit_tag I18n.t('repositories.delete_record'), :class => "hidden
|
||||
delete_repository_records_submit" %>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default copyRow" id="copyRepositoryRecords" onclick="onClickCopyRepositoryRecords()" disabled>
|
||||
<span class="glyphicon glyphicon-duplicate"></span>
|
||||
<span class="hidden-xs-custom"><%= t("repositories.copy_record") %></span>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<% end %>
|
||||
</li>
|
||||
<li class="<%= "active" if repositories_are_selected? %>">
|
||||
<%= link_to repositories_path, id: "repositories-link", title: t('left_menu_bar.repositories') do %>
|
||||
<%= link_to repositories_path, data: { no_turbolink: false }, id: "repositories-link", title: t('left_menu_bar.repositories') do %>
|
||||
<span class="fas fa-cubes" aria-hidden="true"></span>
|
||||
<span><%= t('left_menu_bar.repositories') %></span>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -10,58 +10,6 @@
|
|||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
|
||||
<!-- Breadcrumbs, displayed on small screens -->
|
||||
<ul class="breadcrumb hidden-sm hidden-md hidden-lg">
|
||||
<li>
|
||||
<% if can_read_team?(@project.team) %>
|
||||
<a href="<%= projects_path :team => @project.team.id %>">
|
||||
<span class="glyphicon glyphicon-folder-open"></span>
|
||||
</a>
|
||||
<% else %>
|
||||
<span class="glyphicon glyphicon-folder-open"></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<% if project_page? ||
|
||||
sample_types_page_project? ||
|
||||
sample_groups_page_project? %>
|
||||
<li class="active">
|
||||
<span class="glyphicon glyphicon-blackboard"></span>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<% if can_read_project?(@project) %>
|
||||
<a href="<%= project_url(@project) %>">
|
||||
<span class="glyphicon glyphicon-blackboard"></span>
|
||||
</a>
|
||||
<% else %>
|
||||
<span class="glyphicon glyphicon-blackboard"></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if experiment_page? %>
|
||||
<li class="active">
|
||||
<i class="fas fa-flask"></i>
|
||||
</li>
|
||||
<% elsif module_page? %>
|
||||
<li>
|
||||
<% if can_read_experiment?(@experiment) %>
|
||||
<%= link_to canvas_experiment_path(@experiment) do %>
|
||||
<i class="fas fa-flask"></i>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<i class="fas fa-flask"></i>
|
||||
<% end %>
|
||||
</li>
|
||||
<li class="active">
|
||||
<span class="glyphicon glyphicon-credit-card"></span>
|
||||
</li>
|
||||
<% elsif experiment_page? %>
|
||||
<li class="active">
|
||||
<i class="fas fa-flask"></i>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- buttons -->
|
||||
|
|
@ -212,72 +160,12 @@
|
|||
<% end %>
|
||||
</ul>
|
||||
|
||||
<!-- Breadcrumbs, displayed on large screens -->
|
||||
<ul class="breadcrumb hidden-xs">
|
||||
<li>
|
||||
<% if can_read_team?(@project.team) %>
|
||||
<a href="<%= projects_path :team => @project.team.id %>">
|
||||
<%= truncate(@project.team.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
</a>
|
||||
<% else %>
|
||||
<%= truncate(@project.team.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% if project_page? %>
|
||||
<li class="active">
|
||||
<%= truncate(@project.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<% if can_read_project?(@project) %>
|
||||
<a href="<%= project_url(@project) %>">
|
||||
<%= truncate(@project.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
</a>
|
||||
<% else %>
|
||||
<%= truncate(@project.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if experiment_page? ||
|
||||
module_page? ||
|
||||
sample_types_page_my_module? ||
|
||||
sample_groups_page_my_module? ||
|
||||
sample_groups_page_experiment? ||
|
||||
sample_types_page_expermient? %>
|
||||
<% if !module_page? &&
|
||||
!sample_types_page_my_module? &&
|
||||
!sample_groups_page_my_module? %>
|
||||
<li class="active">
|
||||
<%= truncate(@experiment.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<% if can_read_experiment?(@experiment) %>
|
||||
<%= link_to truncate(@experiment.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH),
|
||||
canvas_experiment_path(@experiment) %>
|
||||
<% else %>
|
||||
<%= truncate(@experiment.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if module_page? ||
|
||||
sample_types_page_my_module? ||
|
||||
sample_groups_page_my_module? %>
|
||||
<li class="active">
|
||||
<%= truncate(@my_module.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<!-- Secondary navigation title -->
|
||||
<div class="nav-name">
|
||||
<%= truncate(title_element.name,
|
||||
length: Constants::NAME_TRUNCATION_LENGTH) %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<div id="slide-panel" class="visible">
|
||||
<div class="tree">
|
||||
<ul>
|
||||
<% if project_page? && action_name == 'index' ||
|
||||
<% if project_page? && action_name.in?(%w(index archive)) ||
|
||||
sample_types_page_project? ||
|
||||
sample_groups_page_project? %>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<% @projects_by_teams.each do |team, projects| %>
|
||||
<% projects.each do |project| %>
|
||||
|
||||
<% if (project_page? && action_name == 'show' ||
|
||||
<% if (project_page? && action_name.in?(%w(show experiment_archive)) ||
|
||||
sample_types_page_project? ||
|
||||
sample_groups_page_project?) && project == @project %>
|
||||
<li class="active" data-parent="candidate">
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ Rails.application.configure do
|
|||
# config.action_dispatch.rack_cache = true
|
||||
|
||||
# Compress JavaScripts and CSS.
|
||||
config.assets.js_compressor = :uglifier
|
||||
config.assets.js_compressor = Uglifier.new(harmony: true)
|
||||
# config.assets.css_compressor = :sass
|
||||
|
||||
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
||||
|
|
|
|||
|
|
@ -168,9 +168,9 @@ class Constants
|
|||
#=============================================================================
|
||||
|
||||
HTTP = 'http://'.freeze
|
||||
TUTORIALS_URL = (HTTP + 'scinote.net/tutorials/').freeze
|
||||
SUPPORT_URL = (HTTP + 'support.scinote.net/hc/en-us').freeze
|
||||
WEBINARS_URL = (HTTP + 'scinote.net/join-a-webinar/').freeze
|
||||
TUTORIALS_URL = (HTTP + 'goo.gl/YH3fXA').freeze
|
||||
SUPPORT_URL = (HTTP + 'goo.gl/Jb9WXx').freeze
|
||||
WEBINARS_URL = (HTTP + 'goo.gl/q3GdND').freeze
|
||||
# Default user picture avatar
|
||||
DEFAULT_AVATAR_URL = '/images/:style/missing.png'.freeze
|
||||
|
||||
|
|
@ -868,6 +868,8 @@ class Constants
|
|||
|
||||
EXPORTABLE_ZIP_EXPIRATION_DAYS = 7
|
||||
|
||||
REPOSITORY_LIST_ITEMS_PER_COLUMN = 500
|
||||
|
||||
# Very basic regex to check for validity of emails
|
||||
BASIC_EMAIL_REGEX = URI::MailTo::EMAIL_REGEXP
|
||||
|
||||
|
|
|
|||
|
|
@ -312,8 +312,8 @@ en:
|
|||
head_title: "%{project} | New report"
|
||||
nav_title: "Report for: "
|
||||
nav_print: "Print"
|
||||
nav_pdf: "Export to PDF"
|
||||
nav_save: "Save report"
|
||||
nav_pdf: "Download PDF"
|
||||
nav_save: "Save"
|
||||
nav_close: "Close"
|
||||
nav_sort_by: "Sort report by"
|
||||
nav_sort_asc: "Oldest on top"
|
||||
|
|
@ -329,7 +329,7 @@ en:
|
|||
tasks_tab: "Choose tasks"
|
||||
content_tab: "Choose content"
|
||||
project_contents_inner:
|
||||
instructions: "Select projects/experiment/tasks to include in the report"
|
||||
instructions: "Select experiments/tasks to include in the report"
|
||||
no_modules: "The project contains no tasks"
|
||||
no_module_group: "No workflow"
|
||||
module_contents:
|
||||
|
|
@ -923,9 +923,6 @@ en:
|
|||
name_placeholder: "My inventory"
|
||||
submit: "Create inventory"
|
||||
success_flash: "Inventory <strong>%{name}</strong> successfully created."
|
||||
nav:
|
||||
breadcrumbs:
|
||||
repositories: "Inventories"
|
||||
table:
|
||||
id: 'ID'
|
||||
assigned: "Assigned"
|
||||
|
|
@ -947,6 +944,7 @@ en:
|
|||
errors_list_title: "Items were not imported because one or more errors were found:"
|
||||
no_repository_name: "Item name is required!"
|
||||
edit_record: "Edit"
|
||||
copy_record: "Copy"
|
||||
delete_record: "Delete"
|
||||
save_record: "Save"
|
||||
cancel_save: "Cancel"
|
||||
|
|
@ -973,7 +971,7 @@ en:
|
|||
delete: "Delete column"
|
||||
modal_parse:
|
||||
title: 'Import items'
|
||||
warning_1: 'Be careful when importing into Dropdown column/s! Each new unique cell value from the file will create a new Dropdown option. This could result in large amounts of Dropdown options.'
|
||||
warning_1: 'Be careful when importing into Dropdown column/s! Each new unique cell value from the file will create a new Dropdown option. Maximum nr. of Dropdown options is %{limit}.'
|
||||
warning_2: 'Importing into file columns is not supported.'
|
||||
modal_import:
|
||||
title: 'Import items'
|
||||
|
|
@ -998,6 +996,7 @@ en:
|
|||
no_records_assigned_flash: "No items were assigned to task"
|
||||
no_records_unassigned_flash: "No items were unassigned from task"
|
||||
default_column: 'Name'
|
||||
copy_records_report: "%{number} item(s) successfully copied."
|
||||
|
||||
libraries:
|
||||
manange_modal_column:
|
||||
|
|
@ -1014,6 +1013,7 @@ en:
|
|||
|
||||
repository_columns:
|
||||
head_title: '%{repository} | Manage Columns'
|
||||
repository_list_items_limit: "Dropdown items limit reached max. %{limit}"
|
||||
update:
|
||||
success_flash: "Column %{name} was successfully updated."
|
||||
create:
|
||||
|
|
@ -1032,6 +1032,7 @@ en:
|
|||
index:
|
||||
head_title: "Inventories"
|
||||
no_libraries:
|
||||
no_permission_title: "You don't have permission to create new inventory. Please contact your team administrator."
|
||||
text: "You don't have any inventories."
|
||||
title: "Please create your first Inventory"
|
||||
create_new_button: "Create New Inventory"
|
||||
|
|
@ -1454,10 +1455,6 @@ en:
|
|||
leave_flash: "Successfuly left team %{team}."
|
||||
|
||||
protocols:
|
||||
nav:
|
||||
breadcrumbs:
|
||||
manager: "Protocol management"
|
||||
edit: "Edit protocol"
|
||||
protocols_io_import:
|
||||
title_too_long: "... Text is too long so we had to cut it off."
|
||||
too_long: "... <span class='label label-warning'>Text is too long so we had to cut it off.</span>"
|
||||
|
|
@ -1660,6 +1657,7 @@ en:
|
|||
row_success: "Archived"
|
||||
row_renamed: "Archived & renamed"
|
||||
row_failed: "Failed"
|
||||
preview: "View"
|
||||
restore_results:
|
||||
title: "Restore results"
|
||||
message_failed: "Failed to restore %{nr} protocols."
|
||||
|
|
|
|||
|
|
@ -466,6 +466,9 @@ Rails.application.routes.draw do
|
|||
to: 'repository_rows#delete_records',
|
||||
as: 'delete_records',
|
||||
defaults: { format: 'json' }
|
||||
post 'copy_records',
|
||||
to: 'repository_rows#copy_records',
|
||||
defaults: { format: 'json' }
|
||||
get 'repository_columns/:id/destroy_html',
|
||||
to: 'repository_columns#destroy_html',
|
||||
as: 'columns_destroy_html'
|
||||
|
|
|
|||
|
|
@ -115,4 +115,12 @@ describe RepositoryRowsController, type: :controller do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #copy_records' do
|
||||
it 'returns a success response' do
|
||||
post :copy_records, params: { repository_id: repository.id,
|
||||
selected_rows: [repository_row.id] }
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ RSpec.describe RepositoryListItem, type: :model do
|
|||
end
|
||||
|
||||
describe 'Validations' do
|
||||
let!(:user) { create :user }
|
||||
let!(:repository_one) { create :repository }
|
||||
it { should validate_presence_of(:data) }
|
||||
it do
|
||||
should validate_length_of(:data).is_at_most(Constants::TEXT_MAX_LENGTH)
|
||||
end
|
||||
|
||||
context 'has a uniq data scoped on repository column' do
|
||||
let!(:user) { create :user }
|
||||
let!(:repository_one) { create :repository }
|
||||
let!(:repository_column) do
|
||||
create :repository_column, name: 'My column', repository: repository_one
|
||||
end
|
||||
|
|
|
|||
83
spec/services/repository_actions/duplicate_rows_spec.rb
Normal file
83
spec/services/repository_actions/duplicate_rows_spec.rb
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe RepositoryActions::DuplicateRows do
|
||||
let!(:user) { create :user }
|
||||
let!(:repository) { create :repository }
|
||||
let!(:list_column) do
|
||||
create(:repository_column, name: 'list',
|
||||
repository: repository,
|
||||
created_by: user,
|
||||
data_type: 'RepositoryListValue')
|
||||
end
|
||||
let!(:text_column) do
|
||||
create(:repository_column, name: 'text',
|
||||
repository: repository,
|
||||
created_by: user,
|
||||
data_type: 'RepositoryTextValue')
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
before do
|
||||
@rows_ids = []
|
||||
|
||||
3.times do |index|
|
||||
row = create :repository_row, name: "row (#{index})",
|
||||
repository: repository
|
||||
create :repository_text_value, data: "text (#{index})",
|
||||
repository_cell_attributes: {
|
||||
repository_row: row,
|
||||
repository_column: text_column
|
||||
}
|
||||
create :repository_list_value,
|
||||
repository_list_item: create(:repository_list_item,
|
||||
repository: repository,
|
||||
repository_column: list_column,
|
||||
data: "list item (#{index})"),
|
||||
repository_cell_attributes: {
|
||||
repository_row: row,
|
||||
repository_column: list_column
|
||||
}
|
||||
@rows_ids << row.id.to_s
|
||||
end
|
||||
end
|
||||
|
||||
it 'generates a duplicate of selected items' do
|
||||
expect(repository.repository_rows.reload.size).to eq 3
|
||||
described_class.new(user, repository, @rows_ids).call
|
||||
expect(repository.repository_rows.reload.size).to eq 6
|
||||
end
|
||||
|
||||
it 'generates an exact duplicate of the row with custom column values' do
|
||||
described_class.new(user, repository, [@rows_ids.first]).call
|
||||
duplicated_row = repository.repository_rows.order('created_at ASC').last
|
||||
expect(duplicated_row.name).to eq 'row (0) (1)'
|
||||
duplicated_row.repository_cells.each do |cell|
|
||||
if cell.value_type == 'RepositoryListValue'
|
||||
expect(cell.value.data).to eq 'list item (0)'
|
||||
else
|
||||
expect(cell.value.data).to eq 'text (0)'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'prevents to duplicate items that do not already belong to repository' do
|
||||
new_repository = create :repository, name: 'new repo'
|
||||
new_row = create :repository_row, name: 'other row',
|
||||
repository: new_repository
|
||||
described_class.new(user, repository, [new_row.id]).call
|
||||
expect(repository.repository_rows.reload.size).to eq 3
|
||||
end
|
||||
|
||||
it 'returns the number of duplicated items' do
|
||||
service_obj = described_class.new(user, repository, @rows_ids)
|
||||
service_obj.call
|
||||
expect(service_obj.number_of_duplicated_items).to eq 3
|
||||
end
|
||||
|
||||
it 'returns the number of duplicated items' do
|
||||
service_obj = described_class.new(user, repository, [])
|
||||
service_obj.call
|
||||
expect(service_obj.number_of_duplicated_items).to eq 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -57,7 +57,7 @@ describe SmartAnnotations::Preview do
|
|||
trimmed_repository_name = subject.__send__(
|
||||
:trim_repository_name, 'banana'
|
||||
)
|
||||
expect(trimmed_repository_name).to eq('BAN')
|
||||
expect(trimmed_repository_name).to eq('Ban')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ describe RepositoryImportParser::RepositoryCellValueResolver do
|
|||
context 'RepositoryListValue' do
|
||||
let(:subject) do
|
||||
RepositoryImportParser::RepositoryCellValueResolver.new(
|
||||
sample_group_column, user, repository
|
||||
sample_group_column, user, repository, 0
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ describe RepositoryImportParser::RepositoryCellValueResolver do
|
|||
context 'RepositoryTextValue' do
|
||||
let(:subject) do
|
||||
RepositoryImportParser::RepositoryCellValueResolver.new(
|
||||
custom_column, user, repository
|
||||
custom_column, user, repository, 0
|
||||
)
|
||||
|
||||
it 'returns a valid RepositoryTextValue object' do
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue