mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-09 14:46:47 +08:00
Merge pull request #1144 from ZmagoD/zd_SCI_2371
adds save PDF report to inventory feature [fixes SCI-2371]
This commit is contained in:
commit
5dbe978d34
18 changed files with 657 additions and 16 deletions
|
@ -210,8 +210,8 @@ var HelperModule = (function(){
|
||||||
}
|
}
|
||||||
|
|
||||||
helpers.flashAlertMsg = function(message, type) {
|
helpers.flashAlertMsg = function(message, type) {
|
||||||
var alertType;
|
var alertType, glyphSign;
|
||||||
var glyphSign;
|
|
||||||
$('#notifications').html('');
|
$('#notifications').html('');
|
||||||
if (type === 'success') {
|
if (type === 'success') {
|
||||||
alertType = ' alert-success ';
|
alertType = ' alert-success ';
|
||||||
|
|
282
app/assets/javascripts/reports/save_pdf_to_inventory.js.erb
Normal file
282
app/assets/javascripts/reports/save_pdf_to_inventory.js.erb
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var INVENTORY_PICKER, COLUMN_PICKER, ITEM_PICKER;
|
||||||
|
var SELECTED_IDS = {
|
||||||
|
repository_id: null,
|
||||||
|
respository_column_id: null,
|
||||||
|
repository_item_id: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
function clearErrors() {
|
||||||
|
var $columnsAlertSection = $('#save-PDF-to-inventory-column-warnings');
|
||||||
|
var $itemsAlertSection = $('#save-PDF-to-inventory-warnings');
|
||||||
|
$itemsAlertSection.empty();
|
||||||
|
$columnsAlertSection.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleHasFileErrorMessage(value) {
|
||||||
|
var element = $('#selectInventoryItem [value="' + value + '"]');
|
||||||
|
var $alertSection = $('#save-PDF-to-inventory-warnings');
|
||||||
|
$alertSection.empty();
|
||||||
|
if(element.data('hasfile')) {
|
||||||
|
$alertSection.append(
|
||||||
|
'<div class="alert alert-danger">' +
|
||||||
|
'<%=I18n.t("projects.reports.new.save_PDF_to_inventory_modal.asset_present_warning_html") %>' +
|
||||||
|
'</div>'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendSearchResults(data) {
|
||||||
|
var items = [];
|
||||||
|
if(data.hasOwnProperty('results')){
|
||||||
|
$.each(data.results, function(index, el) {
|
||||||
|
items.push(
|
||||||
|
{
|
||||||
|
value: el.id,
|
||||||
|
text: el.name,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendSearchResultsForItems(data) {
|
||||||
|
var items = [];
|
||||||
|
if(data.hasOwnProperty('results')){
|
||||||
|
$('#selectInventoryItem').parent().find('button').removeAttr('disabled');
|
||||||
|
$.each(data.results, function(index, el) {
|
||||||
|
items.push(
|
||||||
|
{
|
||||||
|
value: el.id,
|
||||||
|
text: el.name,
|
||||||
|
disabled: false,
|
||||||
|
data: {
|
||||||
|
hasFile: el.hasOwnProperty('has_file_attached') ?
|
||||||
|
el.has_file_attached :
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$('#selectInventoryItem').parent().find('button').attr('disabled', true);
|
||||||
|
clearErrors();
|
||||||
|
$('#save-PDF-to-inventory-warnings').append(
|
||||||
|
'<strong class="danger">' + data.no_items + '</strong>'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendSearchResultsForColumns(data) {
|
||||||
|
var items = [];
|
||||||
|
if(data.hasOwnProperty('results')){
|
||||||
|
$('#selectInventoryColumn').parent().find('button').removeAttr('disabled');
|
||||||
|
$.each(data.results, function(index, el) {
|
||||||
|
items.push(
|
||||||
|
{
|
||||||
|
value: el.id,
|
||||||
|
text: el.name,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$('#selectInventoryColumn').parent().find('button').attr('disabled', true);
|
||||||
|
clearErrors();
|
||||||
|
$('#save-PDF-to-inventory-column-warnings').append(
|
||||||
|
'<div class="save-PDF-to-inventory-alerts"><strong class="danger">' +
|
||||||
|
data.no_items + '</strong></div>'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitButtonEnableToggle(status) {
|
||||||
|
var button = $('#savePDFtoInventorySubmit');
|
||||||
|
if(status) {
|
||||||
|
button.removeAttr('disabled');
|
||||||
|
} else {
|
||||||
|
button.attr('disabled', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deselect(element) {
|
||||||
|
if(element) {
|
||||||
|
element.selectpicker('val', null)
|
||||||
|
element.selectpicker('render');
|
||||||
|
element.attr('disabled', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// triggers first request and cleans the dropdown selectpicker
|
||||||
|
function clearDropdownResultsCallback(element) {
|
||||||
|
element.parent().find('button').on('click', function(el) {
|
||||||
|
$(this).parent().find('input').trigger('keyup');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initInventoryItemSelectPicker() {
|
||||||
|
ITEM_PICKER =
|
||||||
|
$('#selectInventoryItem')
|
||||||
|
.removeAttr('disabled')
|
||||||
|
.selectpicker({liveSearch: true})
|
||||||
|
.ajaxSelectPicker({
|
||||||
|
ajax: {
|
||||||
|
url: '<%= Rails.application.routes.url_helpers.available_rows_path %>',
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
q: '{{{q}}}',
|
||||||
|
repository_id: SELECTED_IDS.repository_id,
|
||||||
|
repository_column_id: SELECTED_IDS.respository_column_id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
emptyTitle: '<%= I18n.t('projects.reports.new.save_PDF_to_inventory_modal.nothing_selected') %>'
|
||||||
|
},
|
||||||
|
preprocessData: appendSearchResultsForItems,
|
||||||
|
emptyRequest: true,
|
||||||
|
clearOnEmpty: true,
|
||||||
|
cache: false,
|
||||||
|
preserveSelected: false
|
||||||
|
}).on('change.bs.select', function(el) {
|
||||||
|
var value = el.target.value;
|
||||||
|
toggleHasFileErrorMessage(value);
|
||||||
|
submitButtonEnableToggle(true);
|
||||||
|
SELECTED_IDS.repository_item_id = value;
|
||||||
|
});
|
||||||
|
clearDropdownResultsCallback(ITEM_PICKER);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initInventoryColumnSelectPicker() {
|
||||||
|
COLUMN_PICKER =
|
||||||
|
$('#selectInventoryColumn')
|
||||||
|
.removeAttr('disabled')
|
||||||
|
.selectpicker({liveSearch: true})
|
||||||
|
.ajaxSelectPicker({
|
||||||
|
ajax: {
|
||||||
|
url: '<%= Rails.application.routes.url_helpers.available_asset_type_columns_path %>',
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
q: '{{{q}}}',
|
||||||
|
repository_id: SELECTED_IDS.repository_id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
emptyTitle: '<%= I18n.t('projects.reports.new.save_PDF_to_inventory_modal.nothing_selected') %>'
|
||||||
|
},
|
||||||
|
preprocessData: appendSearchResultsForColumns,
|
||||||
|
emptyRequest: true,
|
||||||
|
clearOnEmpty: true,
|
||||||
|
cache: false,
|
||||||
|
preserveSelected: false
|
||||||
|
}).on('change.bs.select', function(el) {
|
||||||
|
SELECTED_IDS.respository_column_id = el.target.value;
|
||||||
|
deselect(ITEM_PICKER);
|
||||||
|
submitButtonEnableToggle(false);
|
||||||
|
initInventoryItemSelectPicker();
|
||||||
|
// refresh the dropdown state
|
||||||
|
$('#selectInventoryItem').parent().find('input').trigger('keyup');
|
||||||
|
clearErrors();
|
||||||
|
});
|
||||||
|
clearDropdownResultsCallback(COLUMN_PICKER);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initInventoriesSelectPicker() {
|
||||||
|
INVENTORY_PICKER =
|
||||||
|
$('#selectInventory')
|
||||||
|
.selectpicker({liveSearch: true})
|
||||||
|
.ajaxSelectPicker({
|
||||||
|
ajax: {
|
||||||
|
url: '<%= Rails.application.routes.url_helpers.reports_available_repositories_path %>',
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: function () {
|
||||||
|
return { q: '{{{q}}}' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
emptyTitle: '<%= I18n.t('projects.reports.new.save_PDF_to_inventory_modal.nothing_selected') %>'
|
||||||
|
},
|
||||||
|
preprocessData: appendSearchResults,
|
||||||
|
emptyRequest: true,
|
||||||
|
clearOnEmpty: false,
|
||||||
|
cache: false,
|
||||||
|
preserveSelected: false
|
||||||
|
}).on('change.bs.select', function(el) {
|
||||||
|
SELECTED_IDS.repository_id = el.target.value;
|
||||||
|
deselect(COLUMN_PICKER);
|
||||||
|
deselect(ITEM_PICKER);
|
||||||
|
submitButtonEnableToggle(false);
|
||||||
|
initInventoryColumnSelectPicker();
|
||||||
|
clearErrors();
|
||||||
|
// refresh the dropdown state
|
||||||
|
$('#selectInventoryColumn').parent().find('input').trigger('keyup');
|
||||||
|
});
|
||||||
|
clearDropdownResultsCallback(INVENTORY_PICKER);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeSubmitAction() {
|
||||||
|
$('#savePDFtoInventorySubmit').off().on('click', function() {
|
||||||
|
animateSpinner();
|
||||||
|
$.ajax({
|
||||||
|
url: '<%= Rails.application.routes.url_helpers.reports_save_pdf_to_inventory_item_path %>',
|
||||||
|
data: Object.assign(SELECTED_IDS, { html: $(REPORT_CONTENT).html() }, {}),
|
||||||
|
type: 'POST',
|
||||||
|
success: function(data) {
|
||||||
|
animateSpinner(null, false);
|
||||||
|
HelperModule.flashAlertMsg(data.message, 'success');
|
||||||
|
$('#savePDFtoInventory').modal('hide');
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
animateSpinner(null, false);
|
||||||
|
HelperModule.flashAlertMsg(xhr.responseJSON.message, 'danger');
|
||||||
|
$('#savePDFtoInventory').modal('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INITIALIZERS
|
||||||
|
*/
|
||||||
|
|
||||||
|
function initializeSavePDFtoInventoryModal() {
|
||||||
|
$('#savePDFtoInventory').off().on('shown.bs.modal', function() {
|
||||||
|
initInventoriesSelectPicker();
|
||||||
|
initializeSubmitAction();
|
||||||
|
clearErrors();
|
||||||
|
// refresh the dropdown state
|
||||||
|
$('#selectInventory').parent().find('input').trigger('keyup');
|
||||||
|
}).on('hidden.bs.modal', function() {
|
||||||
|
// clear ids
|
||||||
|
SELECTED_IDS = {
|
||||||
|
repository_id: null,
|
||||||
|
respository_column_id: null,
|
||||||
|
repository_item_id: null,
|
||||||
|
}
|
||||||
|
// clear select picker objects
|
||||||
|
|
||||||
|
if(COLUMN_PICKER) {
|
||||||
|
deselect(COLUMN_PICKER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ITEM_PICKER) {
|
||||||
|
deselect(ITEM_PICKER);
|
||||||
|
}
|
||||||
|
submitButtonEnableToggle(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(initializeSavePDFtoInventoryModal);
|
||||||
|
})();
|
|
@ -537,3 +537,13 @@ label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#save-PDF-to-inventory-warnings {
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-PDF-to-inventory-alerts {
|
||||||
|
.danger {
|
||||||
|
color: $brand-danger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ class ReportsController < ApplicationController
|
||||||
before_action :load_vars, only: %i(edit update)
|
before_action :load_vars, only: %i(edit update)
|
||||||
before_action :load_vars_nested, only: BEFORE_ACTION_METHODS
|
before_action :load_vars_nested, only: BEFORE_ACTION_METHODS
|
||||||
before_action :load_visible_projects, only: %i(index visible_projects)
|
before_action :load_visible_projects, only: %i(index visible_projects)
|
||||||
|
before_action :load_available_repositories,
|
||||||
|
only: %i(new edit available_repositories)
|
||||||
|
|
||||||
before_action :check_manage_permissions, only: BEFORE_ACTION_METHODS
|
before_action :check_manage_permissions, only: BEFORE_ACTION_METHODS
|
||||||
|
|
||||||
|
@ -166,18 +168,40 @@ class ReportsController < ApplicationController
|
||||||
# Generation action
|
# Generation action
|
||||||
# Currently, only .PDF is supported
|
# Currently, only .PDF is supported
|
||||||
def generate
|
def generate
|
||||||
|
content = params[:html]
|
||||||
|
content = I18n.t('projects.reports.new.no_content_for_PDF_html') if content.blank?
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.pdf do
|
format.pdf do
|
||||||
@html = params[:html]
|
render pdf: 'report', header: { right: '[page] of [topage]' },
|
||||||
@html = '<h1>No content</h1>' if @html.blank?
|
locals: { content: content },
|
||||||
render pdf: 'report',
|
template: 'reports/report.pdf.erb',
|
||||||
header: { right: '[page] of [topage]' },
|
disable_javascript: true
|
||||||
template: 'reports/report.pdf.erb',
|
|
||||||
disable_javascript: true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def save_pdf_to_inventory_item
|
||||||
|
save_pdf_to_inventory_item = ReportActions::SavePdfToInventoryItem.new(
|
||||||
|
current_user, current_team, save_PDF_params
|
||||||
|
)
|
||||||
|
if save_pdf_to_inventory_item.save
|
||||||
|
render json: {
|
||||||
|
message: I18n.t(
|
||||||
|
'projects.reports.new.save_PDF_to_inventory_modal.success_flash'
|
||||||
|
)
|
||||||
|
}, status: :ok
|
||||||
|
else
|
||||||
|
render json: { message: save_pdf_to_inventory_item.error_messages },
|
||||||
|
status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
rescue ReportActions::RepositoryPermissionError => error
|
||||||
|
render json: { message: error },
|
||||||
|
status: :forbidden
|
||||||
|
rescue Exception => error
|
||||||
|
render json: { message: error.message },
|
||||||
|
status: :internal_server_error
|
||||||
|
end
|
||||||
|
|
||||||
# Modal for saving the existsing/new report
|
# Modal for saving the existsing/new report
|
||||||
def save_modal
|
def save_modal
|
||||||
# Assume user is updating existing report
|
# Assume user is updating existing report
|
||||||
|
@ -428,10 +452,15 @@ class ReportsController < ApplicationController
|
||||||
render json: { projects: @visible_projects }, status: :ok
|
render json: { projects: @visible_projects }, status: :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def available_repositories
|
||||||
|
render json: { results: @available_repositories }, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
include StringUtility
|
include StringUtility
|
||||||
VisibleProject = Struct.new(:path, :name)
|
VisibleProject = Struct.new(:path, :name)
|
||||||
|
AvailableRepository = Struct.new(:id, :name)
|
||||||
|
|
||||||
def load_vars
|
def load_vars
|
||||||
@report = Report.find_by_id(params[:id])
|
@report = Report.find_by_id(params[:id])
|
||||||
|
@ -456,7 +485,18 @@ class ReportsController < ApplicationController
|
||||||
.select(:id, :name)
|
.select(:id, :name)
|
||||||
@visible_projects = projects.collect do |project|
|
@visible_projects = projects.collect do |project|
|
||||||
VisibleProject.new(new_project_reports_path(project),
|
VisibleProject.new(new_project_reports_path(project),
|
||||||
ellipsisize(project.name, 75, 50))
|
ellipsize(project.name, 75, 50))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_available_repositories
|
||||||
|
repositories = current_team.repositories
|
||||||
|
.name_like(search_params[:q])
|
||||||
|
.limit(Constants::SEARCH_LIMIT)
|
||||||
|
.select(:id, :name)
|
||||||
|
@available_repositories = repositories.collect do |repository|
|
||||||
|
AvailableRepository.new(repository.id,
|
||||||
|
ellipsize(repository.name, 75, 50))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -468,4 +508,11 @@ class ReportsController < ApplicationController
|
||||||
def search_params
|
def search_params
|
||||||
params.permit(:q)
|
params.permit(:q)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def save_PDF_params
|
||||||
|
params.permit(:repository_id,
|
||||||
|
:respository_column_id,
|
||||||
|
:repository_item_id,
|
||||||
|
:html)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
class RepositoryColumnsController < ApplicationController
|
class RepositoryColumnsController < ApplicationController
|
||||||
include InputSanitizeHelper
|
include InputSanitizeHelper
|
||||||
|
ACTIONS = %i(create index create_html available_asset_type_columns).freeze
|
||||||
before_action :load_vars, except: %i(create index create_html)
|
before_action :load_vars,
|
||||||
before_action :load_vars_nested, only: %i(create index create_html)
|
except: ACTIONS
|
||||||
|
before_action :load_vars_nested,
|
||||||
|
only: ACTIONS
|
||||||
before_action :check_create_permissions, only: :create
|
before_action :check_create_permissions, only: :create
|
||||||
before_action :check_manage_permissions, except: %i(create index create_html)
|
before_action :check_manage_permissions,
|
||||||
|
except: ACTIONS
|
||||||
before_action :load_repository_columns, only: :index
|
before_action :load_repository_columns, only: :index
|
||||||
|
before_action :load_asset_type_columns, only: :available_asset_type_columns
|
||||||
|
|
||||||
def index; end
|
def index; end
|
||||||
|
|
||||||
|
@ -139,8 +143,23 @@ class RepositoryColumnsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def available_asset_type_columns
|
||||||
|
if @asset_columns.empty?
|
||||||
|
render json: {
|
||||||
|
no_items: t(
|
||||||
|
'projects.reports.new.save_PDF_to_inventory_modal.no_columns'
|
||||||
|
)
|
||||||
|
}, status: :ok
|
||||||
|
else
|
||||||
|
render json: { results: @asset_columns }, status: :ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
include StringUtility
|
||||||
|
AvailableRepositoryColumn = Struct.new(:id, :name)
|
||||||
|
|
||||||
def load_vars
|
def load_vars
|
||||||
@repository = Repository.find_by_id(params[:repository_id])
|
@repository = Repository.find_by_id(params[:repository_id])
|
||||||
render_404 unless @repository
|
render_404 unless @repository
|
||||||
|
@ -158,6 +177,11 @@ class RepositoryColumnsController < ApplicationController
|
||||||
.order(created_at: :desc)
|
.order(created_at: :desc)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def load_asset_type_columns
|
||||||
|
render_403 unless can_read_team?(@repository.team)
|
||||||
|
@asset_columns = load_asset_columns(search_params[:q])
|
||||||
|
end
|
||||||
|
|
||||||
def check_create_permissions
|
def check_create_permissions
|
||||||
render_403 unless can_create_repository_columns?(@repository.team)
|
render_403 unless can_create_repository_columns?(@repository.team)
|
||||||
end
|
end
|
||||||
|
@ -170,6 +194,23 @@ class RepositoryColumnsController < ApplicationController
|
||||||
params.require(:repository_column).permit(:name, :data_type)
|
params.require(:repository_column).permit(:name, :data_type)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def search_params
|
||||||
|
params.permit(:q, :repository_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_asset_columns(query)
|
||||||
|
@repository.repository_columns
|
||||||
|
.asset_type.name_like(query)
|
||||||
|
.limit(Constants::SEARCH_LIMIT)
|
||||||
|
.select(:id, :name)
|
||||||
|
.collect do |column|
|
||||||
|
AvailableRepositoryColumn.new(
|
||||||
|
column.id,
|
||||||
|
ellipsize(column.name, 75, 50)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def generate_repository_list_items(item_names)
|
def generate_repository_list_items(item_names)
|
||||||
return true unless @repository_column.data_type == 'RepositoryListValue'
|
return true unless @repository_column.data_type == 'RepositoryListValue'
|
||||||
column_items = @repository_column.repository_list_items.size
|
column_items = @repository_column.repository_list_items.size
|
||||||
|
|
|
@ -6,7 +6,11 @@ class RepositoryRowsController < ApplicationController
|
||||||
before_action :load_info_modal_vars, only: :show
|
before_action :load_info_modal_vars, only: :show
|
||||||
before_action :load_vars, only: %i(edit update)
|
before_action :load_vars, only: %i(edit update)
|
||||||
before_action :load_repository,
|
before_action :load_repository,
|
||||||
only: %i(create delete_records index copy_records)
|
only: %i(create
|
||||||
|
delete_records
|
||||||
|
index
|
||||||
|
copy_records
|
||||||
|
available_rows)
|
||||||
before_action :check_create_permissions, only: :create
|
before_action :check_create_permissions, only: :create
|
||||||
before_action :check_manage_permissions,
|
before_action :check_manage_permissions,
|
||||||
only: %i(edit update delete_records copy_records)
|
only: %i(edit update delete_records copy_records)
|
||||||
|
@ -297,8 +301,26 @@ class RepositoryRowsController < ApplicationController
|
||||||
}, status: :ok
|
}, status: :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def available_rows
|
||||||
|
if @repository.repository_rows.empty?
|
||||||
|
no_items_string =
|
||||||
|
"#{t('projects.reports.new.save_PDF_to_inventory_modal.no_items')} " \
|
||||||
|
"#{link_to(t('projects.reports.new.save_PDF_to_inventory_modal.here'),
|
||||||
|
repository_path(@repository),
|
||||||
|
data: { 'no-turbolink' => true })}"
|
||||||
|
render json: { no_items: no_items_string },
|
||||||
|
status: :ok
|
||||||
|
else
|
||||||
|
render json: { results: load_available_rows(search_params[:q]) },
|
||||||
|
status: :ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
include StringUtility
|
||||||
|
AvailableRepositoryRow = Struct.new(:id, :name, :has_file_attached)
|
||||||
|
|
||||||
def load_info_modal_vars
|
def load_info_modal_vars
|
||||||
@repository_row = RepositoryRow.eager_load(:created_by, repository: [:team])
|
@repository_row = RepositoryRow.eager_load(:created_by, repository: [:team])
|
||||||
.find_by_id(params[:id])
|
.find_by_id(params[:id])
|
||||||
|
@ -343,6 +365,27 @@ class RepositoryRowsController < ApplicationController
|
||||||
params.permit(selected_rows: []).to_h[:selected_rows]
|
params.permit(selected_rows: []).to_h[:selected_rows]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def load_available_rows(query)
|
||||||
|
@repository.repository_rows
|
||||||
|
.includes(:repository_cells)
|
||||||
|
.name_like(search_params[:q])
|
||||||
|
.limit(Constants::SEARCH_LIMIT)
|
||||||
|
.select(:id, :name)
|
||||||
|
.collect do |row|
|
||||||
|
with_asset_cell = row.repository_cells.where(
|
||||||
|
'repository_cells.repository_column_id = ?',
|
||||||
|
search_params[:repository_column_id]
|
||||||
|
)
|
||||||
|
AvailableRepositoryRow.new(row.id,
|
||||||
|
ellipsize(row.name, 75, 50),
|
||||||
|
with_asset_cell.present?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def search_params
|
||||||
|
params.permit(:q, :repository_id, :repository_column_id)
|
||||||
|
end
|
||||||
|
|
||||||
def record_annotation_notification(record, cell, old_text = nil)
|
def record_annotation_notification(record, cell, old_text = nil)
|
||||||
table_url = params.fetch(:request_url) { :request_url_must_be_present }
|
table_url = params.fetch(:request_url) { :request_url_must_be_present }
|
||||||
smart_annotation_notification(
|
smart_annotation_notification(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module StringUtility
|
module StringUtility
|
||||||
def ellipsisize(
|
def ellipsize(
|
||||||
string,
|
string,
|
||||||
minimum_length = Constants::MAX_NAME_TRUNCATION,
|
minimum_length = Constants::MAX_NAME_TRUNCATION,
|
||||||
edge_length = Constants::MAX_EDGE_LENGTH
|
edge_length = Constants::MAX_EDGE_LENGTH
|
||||||
|
|
|
@ -57,6 +57,10 @@ class Repository < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.name_like(query)
|
||||||
|
where('repositories.name ILIKE ?', "%#{query}%")
|
||||||
|
end
|
||||||
|
|
||||||
def importable_repository_fields
|
def importable_repository_fields
|
||||||
fields = {}
|
fields = {}
|
||||||
# First and foremost add record name
|
# First and foremost add record name
|
||||||
|
|
|
@ -23,6 +23,11 @@ class RepositoryColumn < ApplicationRecord
|
||||||
around_destroy :update_repository_table_states_with_removed_column
|
around_destroy :update_repository_table_states_with_removed_column
|
||||||
|
|
||||||
scope :list_type, -> { where(data_type: 'RepositoryListValue') }
|
scope :list_type, -> { where(data_type: 'RepositoryListValue') }
|
||||||
|
scope :asset_type, -> { where(data_type: 'RepositoryAssetValue') }
|
||||||
|
|
||||||
|
def self.name_like(query)
|
||||||
|
where('repository_columns.name ILIKE ?', "%#{query}%")
|
||||||
|
end
|
||||||
|
|
||||||
def update_repository_table_states_with_new_column
|
def update_repository_table_states_with_new_column
|
||||||
service = RepositoryTableStateColumnUpdateService.new
|
service = RepositoryTableStateColumnUpdateService.new
|
||||||
|
|
|
@ -26,4 +26,8 @@ class RepositoryRow < ApplicationRecord
|
||||||
where(id: ids).joins(:my_module_repository_rows)
|
where(id: ids).joins(:my_module_repository_rows)
|
||||||
.where('my_module_repository_rows.my_module' => my_module)
|
.where('my_module_repository_rows.my_module' => my_module)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.name_like(query)
|
||||||
|
where('repository_rows.name ILIKE ?', "%#{query}%")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
113
app/services/report_actions/save_pdf_to_inventory_item.rb
Normal file
113
app/services/report_actions/save_pdf_to_inventory_item.rb
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module ReportActions
|
||||||
|
class SavePdfToInventoryItem
|
||||||
|
|
||||||
|
def initialize(user, team, params)
|
||||||
|
@user = user
|
||||||
|
@team = team
|
||||||
|
@params = params
|
||||||
|
load_repository_collaborators
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
file_path = generate_pdf(@params[:html])
|
||||||
|
asset = create_new_asset(file_path)
|
||||||
|
cell = fetch_repository_cell
|
||||||
|
cell.destroy if cell
|
||||||
|
@new_cell_value = create_new_cell_value(asset)
|
||||||
|
@new_cell_value.save
|
||||||
|
end
|
||||||
|
|
||||||
|
def error_messages
|
||||||
|
return I18n.t('general.error') unless @new_cell_value
|
||||||
|
@new_cell_value.errors.full_messages.join
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
include Canaid::Helpers::PermissionsHelper
|
||||||
|
|
||||||
|
def load_repository_collaborators
|
||||||
|
@repository = load_repository
|
||||||
|
@repository_column = load_repository_column
|
||||||
|
@repository_item = load_repository_item
|
||||||
|
unless can_create_repository_rows?(@user, @repository.team)
|
||||||
|
raise ReportActions::RepositoryPermissionError,
|
||||||
|
I18n.t('projects.reports.new.no_permissions')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_pdf(content)
|
||||||
|
file_path = create_temporary_file
|
||||||
|
pdf_file = WickedPdf.new.pdf_from_string(
|
||||||
|
action_view_context.render(
|
||||||
|
template: 'reports/report.pdf.erb',
|
||||||
|
locals: { content: prepare_pdf_content(content) }
|
||||||
|
),
|
||||||
|
header: { right: '[page] of [topage]' },
|
||||||
|
disable_javascript: true
|
||||||
|
)
|
||||||
|
File.open(file_path, 'wb') do |file|
|
||||||
|
file << pdf_file
|
||||||
|
end
|
||||||
|
file_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_new_asset(file_path)
|
||||||
|
asset = Asset.new(
|
||||||
|
file: file_path, created_by: @user, last_modified_by: @user, team: @team
|
||||||
|
)
|
||||||
|
asset.post_process_file(@team) if asset.save
|
||||||
|
asset
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_repository_cell
|
||||||
|
RepositoryCell.where(repository_row: @repository_item,
|
||||||
|
repository_column: @repository_column,
|
||||||
|
value_type: 'RepositoryAssetValue').first
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_new_cell_value(asset)
|
||||||
|
RepositoryAssetValue.new(
|
||||||
|
asset: asset,
|
||||||
|
created_by: @user,
|
||||||
|
last_modified_by: @user,
|
||||||
|
repository_cell_attributes: {
|
||||||
|
repository_row: @repository_item,
|
||||||
|
repository_column: @repository_column
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_repository
|
||||||
|
Repository.find_by_id(@params[:repository_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_repository_column
|
||||||
|
RepositoryColumn.find_by_id(@params[:respository_column_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_repository_item
|
||||||
|
RepositoryRow.find_by_id(@params[:repository_item_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def action_view_context
|
||||||
|
av = ActionView::Base.new(ActionController::Base.view_paths, {})
|
||||||
|
av.extend ReportsHelper # include reports helper methods to view
|
||||||
|
av.extend InputSanitizeHelper # include input sanitize methods to view
|
||||||
|
av
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_temporary_file
|
||||||
|
Tempfile.open(['report', '.pdf'], Rails.root.join('tmp'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_pdf_content(content)
|
||||||
|
return content unless content.blank?
|
||||||
|
I18n.t('projects.reports.new.no_content_for_PDF_html')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RepositoryPermissionError = Class.new(StandardError)
|
||||||
|
end
|
|
@ -1,5 +1,6 @@
|
||||||
<% provide(:head_title, t("projects.reports.new.head_title", project: h(@project.name)).html_safe) %>
|
<% provide(:head_title, t("projects.reports.new.head_title", project: h(@project.name)).html_safe) %>
|
||||||
|
|
||||||
|
<div id="notifications"></div>
|
||||||
<%= render partial: "reports/new/report_navigation" %>
|
<%= render partial: "reports/new/report_navigation" %>
|
||||||
|
|
||||||
<div class="content-pane" id="report-new">
|
<div class="content-pane" id="report-new">
|
||||||
|
@ -72,8 +73,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<%= render partial: 'reports/new/save_PDF_to_inventory_modal' %>
|
||||||
|
|
||||||
<%= javascript_include_tag "handsontable.full.min" %>
|
<%= javascript_include_tag "handsontable.full.min" %>
|
||||||
<%= javascript_include_tag("reports/new") %>
|
<%= javascript_include_tag("reports/new") %>
|
||||||
|
<%= javascript_include_tag 'reports/save_pdf_to_inventory' %>
|
||||||
|
|
||||||
<!-- Libraries for formulas -->
|
<!-- Libraries for formulas -->
|
||||||
<%= javascript_include_tag "lodash" %>
|
<%= javascript_include_tag "lodash" %>
|
||||||
|
|
|
@ -27,6 +27,12 @@
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onclick="$('#savePDFtoInventory').modal('show')"
|
||||||
|
class="btn btn-default">
|
||||||
|
<%=t 'projects.reports.new.save_PDF_to_inventory'%>
|
||||||
|
</button>
|
||||||
|
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<%= link_to reports_path, data: { no_turbolink: false }, id: "cancel-report-link", class: "btn btn-default" do %>
|
<%= link_to reports_path, data: { no_turbolink: false }, id: "cancel-report-link", class: "btn btn-default" do %>
|
||||||
<span class="hidden-xs"><%=t "projects.reports.new.nav_close" %></span>
|
<span class="hidden-xs"><%=t "projects.reports.new.nav_close" %></span>
|
||||||
|
|
53
app/views/reports/new/_save_PDF_to_inventory_modal.html.erb
Normal file
53
app/views/reports/new/_save_PDF_to_inventory_modal.html.erb
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<div
|
||||||
|
id="savePDFtoInventory"
|
||||||
|
class="modal fade" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title"><%=t 'projects.reports.new.save_PDF_to_inventory' %></h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p><%=t 'projects.reports.new.save_PDF_to_inventory_modal.description_one' %></p>
|
||||||
|
<br />
|
||||||
|
<p><%=t 'projects.reports.new.save_PDF_to_inventory_modal.description_two' %></p>
|
||||||
|
|
||||||
|
<% if @available_repositories && @available_repositories.length > 0 %>
|
||||||
|
<label><%=t 'projects.reports.new.save_PDF_to_inventory_modal.inventory' %></label>
|
||||||
|
<select
|
||||||
|
id="selectInventory"
|
||||||
|
class="form-control selectpicker"
|
||||||
|
data-live-search="true">
|
||||||
|
</select>
|
||||||
|
<label><%=t 'projects.reports.new.save_PDF_to_inventory_modal.inventory_column' %></label>
|
||||||
|
<select
|
||||||
|
id="selectInventoryColumn"
|
||||||
|
class="form-control selectpicker"
|
||||||
|
data-live-search="true"
|
||||||
|
disabled>
|
||||||
|
</select>
|
||||||
|
<div id="save-PDF-to-inventory-column-warnings"></div>
|
||||||
|
<label><%=t 'projects.reports.new.save_PDF_to_inventory_modal.inventory_item' %></label>
|
||||||
|
<select
|
||||||
|
id="selectInventoryItem"
|
||||||
|
class="form-control selectpicker"
|
||||||
|
data-live-search="true"
|
||||||
|
disabled>
|
||||||
|
</select>
|
||||||
|
<% else %>
|
||||||
|
<p><%=t 'projects.reports.new.save_PDF_to_inventory_modal.no_inventories' %></p>
|
||||||
|
<% end %>
|
||||||
|
<div class="save-PDF-to-inventory-alerts" id="save-PDF-to-inventory-warnings"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal"><%=t 'general.cancel' %></button>
|
||||||
|
<button
|
||||||
|
id="savePDFtoInventorySubmit"
|
||||||
|
type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
disabled
|
||||||
|
><%=t 'general.save' %></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -10,7 +10,7 @@
|
||||||
<body class="print-report-body">
|
<body class="print-report-body">
|
||||||
<div class="print-report">
|
<div class="print-report">
|
||||||
<% # Also whitelist <img> and <input type="checkbox"> tags %>
|
<% # Also whitelist <img> and <input type="checkbox"> tags %>
|
||||||
<%= sanitize_input(fix_smart_annotation_image(@html),
|
<%= sanitize_input(fix_smart_annotation_image(content),
|
||||||
%w(img input),
|
%w(img input),
|
||||||
%w(type disabled checked)) %>
|
%w(type disabled checked)) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -87,6 +87,7 @@ Rails.application.config.assets.precompile += %w(repository_columns/index.js)
|
||||||
Rails.application.config.assets.precompile += %w(repositories/show.js)
|
Rails.application.config.assets.precompile += %w(repositories/show.js)
|
||||||
Rails.application.config.assets.precompile += %w(sidebar_toggle.js)
|
Rails.application.config.assets.precompile += %w(sidebar_toggle.js)
|
||||||
Rails.application.config.assets.precompile += %w(reports/reports_datatable.js)
|
Rails.application.config.assets.precompile += %w(reports/reports_datatable.js)
|
||||||
|
Rails.application.config.assets.precompile += %w(reports/save_pdf_to_inventory.js)
|
||||||
|
|
||||||
# Libraries needed for Handsontable formulas
|
# Libraries needed for Handsontable formulas
|
||||||
Rails.application.config.assets.precompile += %w(lodash.js)
|
Rails.application.config.assets.precompile += %w(lodash.js)
|
||||||
|
|
|
@ -318,6 +318,7 @@ en:
|
||||||
nav_title: "Report for: "
|
nav_title: "Report for: "
|
||||||
nav_print: "Print"
|
nav_print: "Print"
|
||||||
nav_pdf: "Download PDF"
|
nav_pdf: "Download PDF"
|
||||||
|
save_PDF_to_inventory: "Save PDF to Inventory"
|
||||||
nav_save: "Save"
|
nav_save: "Save"
|
||||||
nav_close: "Cancel"
|
nav_close: "Cancel"
|
||||||
nav_sort_by: "Sort by"
|
nav_sort_by: "Sort by"
|
||||||
|
@ -327,6 +328,21 @@ en:
|
||||||
sidebar_title: "Navigation"
|
sidebar_title: "Navigation"
|
||||||
global_sort: "Sorting whole report will undo any custom sorting you might have done. Proceed?"
|
global_sort: "Sorting whole report will undo any custom sorting you might have done. Proceed?"
|
||||||
unsaved_work: "Are you sure you want to leave this page? All unsaved data will be lost."
|
unsaved_work: "Are you sure you want to leave this page? All unsaved data will be lost."
|
||||||
|
no_content_for_PDF_html: "<h1>No content</h1>"
|
||||||
|
no_permissions: "You don't have permissions on that repository"
|
||||||
|
save_PDF_to_inventory_modal:
|
||||||
|
description_one: "Here you can save PDF report to an inventory item."
|
||||||
|
description_two: "First select an inventory, then a column and finally the item within the inventory to which you would like to save the PDF report to. Note that the column has to be of type \"file\"."
|
||||||
|
inventory: "Select inventory:"
|
||||||
|
inventory_column: "Select inventory column:"
|
||||||
|
inventory_item: "Select inventory item:"
|
||||||
|
no_inventories: "No inventories available!"
|
||||||
|
success_flash: "Report successfully saved to Inventory item."
|
||||||
|
asset_present_warning_html: "The selected cell already contains a file. If you would like to replace the file click Save. Replacing the file will have the following consequences: <ul><li>previous file will be permanently deleted;</li><li>new file will be added to the Inventory item.</li></ul>"
|
||||||
|
no_items: "Selected Inventory does not contain any items yet. Add the first item"
|
||||||
|
here: "here"
|
||||||
|
no_columns: "You do not have any Inventories with File columns. Add a File column to existing Inventory or create a new Inventory."
|
||||||
|
nothing_selected: "Nothing selected"
|
||||||
elements:
|
elements:
|
||||||
modals:
|
modals:
|
||||||
project_contents:
|
project_contents:
|
||||||
|
@ -1915,6 +1931,7 @@ en:
|
||||||
length_too_short: "Search query is too short (minimum is %{min_length} characters)"
|
length_too_short: "Search query is too short (minimum is %{min_length} characters)"
|
||||||
busy: "The server is still processing your request. If you leave this page, the changes will be lost! Are you sure you want to continue?"
|
busy: "The server is still processing your request. If you leave this page, the changes will be lost! Are you sure you want to continue?"
|
||||||
no_name: "(no name)"
|
no_name: "(no name)"
|
||||||
|
error: "An error has occurred, please try again later."
|
||||||
filter: "Filter:"
|
filter: "Filter:"
|
||||||
|
|
||||||
api:
|
api:
|
||||||
|
|
|
@ -193,6 +193,14 @@ Rails.application.routes.draw do
|
||||||
get 'reports/datatable', to: 'reports#datatable'
|
get 'reports/datatable', to: 'reports#datatable'
|
||||||
post 'reports/visible_projects', to: 'reports#visible_projects',
|
post 'reports/visible_projects', to: 'reports#visible_projects',
|
||||||
defaults: { format: 'json' }
|
defaults: { format: 'json' }
|
||||||
|
post 'reports/available_repositories', to: 'reports#available_repositories',
|
||||||
|
defaults: { format: 'json' }
|
||||||
|
post 'reports/save_pdf_to_inventory_item',
|
||||||
|
to: 'reports#save_pdf_to_inventory_item',
|
||||||
|
defaults: { format: 'json' }
|
||||||
|
post 'available_asset_type_columns',
|
||||||
|
to: 'repository_columns#available_asset_type_columns',
|
||||||
|
defaults: { format: 'json' }
|
||||||
post 'reports/destroy', to: 'reports#destroy'
|
post 'reports/destroy', to: 'reports#destroy'
|
||||||
|
|
||||||
resources :projects, except: [:new, :destroy] do
|
resources :projects, except: [:new, :destroy] do
|
||||||
|
@ -491,6 +499,9 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post 'available_rows', to: 'repository_rows#available_rows',
|
||||||
|
defaults: { format: 'json' }
|
||||||
|
|
||||||
post 'repository_list_items', to: 'repository_list_items#search',
|
post 'repository_list_items', to: 'repository_list_items#search',
|
||||||
defaults: { format: 'json' }
|
defaults: { format: 'json' }
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue