Add print feature to protocols [SCI-6028] (#3700)

* Add print feature to protocols [SCI-6028]

* Close tab after closing print dialog [SCI-6028]

* CSS linter fixes [SCI-6028]
This commit is contained in:
artoscinote 2021-12-01 11:16:45 +01:00 committed by GitHub
parent 16b3ee3d94
commit 9937d1d913
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 380 additions and 1 deletions

View file

@ -45,6 +45,7 @@
//= require activestorage
//= require global_activities/side_pane
//= require protocols/header
//= require protocols/print
//= require marvinjslauncher
//= require jstree.min
//= require_tree ./repositories/renderers
@ -56,7 +57,6 @@
//= require sidebar
//= require turbolinks
// Initialize links for submitting forms. This is useful for submitting
// forms with clicking on links outside form in cases when other than
// GET method is used.

View file

@ -0,0 +1,3 @@
$(document).on('submit', '#print-protocol-form', function() {
$('#print-protocol-modal').modal('hide');
});

View file

@ -0,0 +1,191 @@
@import "shared_styles/constants/*";
@import "constants";
@page {
size: A4;
margin: 8mm;
}
body {
font-family: Lato, "Open Sans", Arial, Helvetica, sans-serif;
font-size: 16px;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.print-protocol-header {
font-size: .8em;
img {
height: .8em;
}
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.3em;
.fa-check-circle {
color: $brand-success;
font-size: 1.3em;
}
}
h3 {
font-size: 1em;
}
hr {
background-color: $color-alto;
border-width: 0;
height: 1px;
}
.print-step {
margin: 5em 0;
}
.step-check-circle {
border-radius: 50%;
border: .15em solid $color-alto;
color: $color-white;
display: inline-block;
height: 1.1em;
text-align: center;
vertical-align: text-bottom;
width: 1.1em;
&.checked {
background-color: $brand-success;
border-color: $brand-success;
}
}
.print-checklist-item {
margin-bottom: 1em;
span {
display: inline-block;
vertical-align: top;
}
}
.checklist-checkbox {
border: .15em solid $color-alto;
border-radius: .2em;
display: inline-block;
height: 1em;
text-align: center;
width: 1em;
&.checked {
background-color: $brand-primary;
border-color: $brand-primary;
color: $color-white;
font-size: 1em;
}
}
.print-table {
border-collapse: collapse;
text-align: center;
width: 100%;
&,
td,
th {
border: 1px solid $color-silver-chalice;
}
th {
font-weight: normal;
}
th,
td:first-child {
background: $color-concrete;
}
td {
padding: .15em .3em;
}
}
.print-asset {
margin: 1em;
p {
font-style: italic;
}
&.thumbnail {
float: left;
padding: 1em;
}
&.thumbnail,
&.list {
border: 1px solid $color-silver-chalice;
}
&.list {
padding: .5em 1em;
}
&.inline {
margin: 5em 0;
text-align: center;
img {
max-width: 100%;
}
}
}
.print-thumbnails {
clear: both;
overflow: hidden;
}
.print-asset-icon {
display: inline-block;
font-size: $font-size-h2;
text-align: center;
width: 24px;
.fa-file-pdf {
color: $pdf-color;
}
.fa-image {
color: $brand-primary;
}
}
.print-comments {
margin-bottom: 5em;
}
.print-comment-container {
margin-bottom: 1em;
}
.print-comment-header {
.user-avatar {
float: left;
margin-right: 1em;
}
.user-name {
color: $color-silver-chalice;
}
}
.print-comment-footer {
color: $color-silver-chalice;
font-size: .8em;
text-align: right;
}

View file

@ -8,6 +8,7 @@
display: inline-block;
height: var(--sci-checkbox-size);
position: relative;
vertical-align: middle;
width: var(--sci-checkbox-size);
}

View file

@ -11,6 +11,8 @@ class ProtocolsController < ApplicationController
include TeamsHelper
include CommentHelper
layout 'protocols/print', only: :print
before_action :check_create_permissions, only: %i(
create_new_modal
create
@ -108,6 +110,11 @@ class ProtocolsController < ApplicationController
end
end
def print
@protocol = Protocol.find(params[:id])
render_403 && return unless @protocol.my_module.blank? || can_read_protocol_in_module?(@protocol)
end
def linked_children
respond_to do |format|
format.json do

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title><%= t("protocols.print.title") %></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<%= stylesheet_link_tag 'print_protocol', media: 'print, screen' %>
<body>
<%= yield %>
<script>
window.print();
window.onfocus=function(){ window.close(); }
</script>
</body>
</html>

View file

@ -121,6 +121,7 @@
<span><%=t "protocols.steps.new_step" %></span>
</a>
<% end %>
<%= render partial: "my_modules/protocols/print_protocol_button", locals: { protocol: @protocol } %>
<%= render partial: "my_modules/protocols/protocol_options_dropdown" %>
</div>
</div>

View file

@ -0,0 +1,35 @@
<a href="#" class="btn btn-default" data-toggle="modal" data-target="#print-protocol-modal">
<span class="fas fa-print" aria-hidden="true"></span>
<span><%=t "protocols.print.button" %></span>
</a>
<div class="modal"
id="print-protocol-modal"
tabindex="-1"
role="dialog"
aria-labelledby="print-protocol-modal-label">
<%= bootstrap_form_tag({ url: print_protocol_path(protocol), method: :get, html: { class: 'print-protocol-form', id: "print-protocol-form", target: '_blank' } }) do %>
<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">&times;</span></button>
<h4 class="modal-title" id="print-protocol-modal-label"><%= t("protocols.print.modal.title") %></h5>
</div>
<div class="modal-body">
<p><%= t("protocols.print.modal.content") %></p>
<div class="sci-checkbox-container">
<%= check_box_tag :include_comments, 1, true, { class: "sci-checkbox" } %>
<span class="sci-checkbox-label"></span>
</div>
<small><%= t("protocols.print.modal.include_comments") %></small>
</div>
<div class="modal-footer">
<div class="pull-right">
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%=t "general.cancel" %></button>
<input type="submit" value="<%= t("protocols.print.button") %>", class="btn btn-primary">
</div>
</div>
</div>
</div>
<% end %>
</div>

View file

@ -0,0 +1,115 @@
<p class="print-protocol-header">
<span><%= t('.header.printed_from') %></span>
<span class="print-protocol-header__logo">
<%= image_tag 'logo.png' %>
</span>
<span><%= t('.header.print_info', datetime: l(DateTime.current, format: :full), full_name: current_user.full_name) %></span>
</p>
<h1><%= @protocol.name || @protocol.my_module.name %></h1>
<div><%= @protocol.description.html_safe %></div>
<% @protocol.steps.order(position: :asc).each do |step| %>
<div class="print-step">
<h2>
<div class="step-check-circle <%= 'checked' if step.completed_on %>">
<% if step.completed_on %>✓<% end %>
</div>
<%= step.position + 1 %>. <%= step.name %>
</h2>
<div><%= step.description.html_safe %></div>
<% step.checklists.each do |checklist| %>
<div class="print-checklist">
<h3><%= checklist.name %></h3>
<% checklist.checklist_items.order(position: :asc).each do |checklist_item| %>
<div class="print-checklist-item">
<span class="checklist-checkbox <%= 'checked' if checklist_item.checked %>">
<% if checklist_item.checked %>
<% end %>
</span>
<span><%= checklist_item.text %></span>
</div>
<% end %>
</div>
<% end %>
<% step.tables.each do |table| %>
<% table_data = JSON.parse(table.contents)["data"] %>
<h3><%= table.name %></h3>
<table class="print-table">
<thead>
<tr>
<th></th>
<% col = "A" %>
<% table_data[0].length.times do %>
<th><%= col %></th>
<% col.succ! %>
<% end %>
</tr>
</thead>
<tbody>
<% table_data.each_with_index do |tr, row| %>
<tr>
<td><%= row + 1 %></td>
<% tr.each do |td| %>
<td><%= td %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
<% end %>
<% step.assets.where(view_mode: "inline").each do |asset| %>
<div class="print-asset inline">
<div class="print-asset-image">
<%= image_tag asset.blob.url %>
<p><%= asset.blob.filename %></p>
</div>
</div>
<% end %>
<% step.assets.where(view_mode: "list").each do |asset| %>
<div class="print-asset list">
<span class="print-asset-icon"><%= file_extension_icon_html(asset) %></span>
<span><%= asset.blob.filename %></span>
</div>
<% end %>
<div class="print-thumbnails">
<% step.assets.where(view_mode: "thumbnail").each do |asset| %>
<div class="print-asset thumbnail">
<div class="print-asset-image">
<%= image_tag asset.blob.representation(resize_to_limit: Constants::MEDIUM_PIC_FORMAT).processed %>
<p><%= asset.blob.filename %></p>
</div>
</div>
<% end %>
</div>
</div>
<% if params[:include_comments] && step.comments.present? %>
<div class="print-comments">
<h3><%= t('Comments') %>:</h3>
<% step.step_comments.each do |comment| %>
<div class="print-comment-container">
<div class="print-comment-header">
<%= image_tag avatar_path(comment.user, :icon_small), class: 'user-avatar' %>
<div class="user-name">
<%= comment.user.full_name %>
</div>
</div>
<div class="print-comment-body">
<div class="comment-message">
<%= comment.message %>
</div>
<div class="print-comment-footer">
<div class="print-comment-create-date">
<%= I18n.l(comment.created_at, format: :full) %>
</div>
</div>
</div>
</div>
<% end %>
</div>
<% end %>
<hr>
<% end %>

View file

@ -69,6 +69,7 @@ Rails.application.config.assets.precompile += %w(datatables.css)
Rails.application.config.assets.precompile += %w(my_modules.js)
Rails.application.config.assets.precompile += %w(Sortable.min.js)
Rails.application.config.assets.precompile += %w(reports_pdf.css)
Rails.application.config.assets.precompile += %w(print_protocol.css)
Rails.application.config.assets.precompile += %w(jszip.min.js)
Rails.application.config.assets.precompile += %w(comments.js)
Rails.application.config.assets.precompile += %w(projects/show.js)

View file

@ -2002,6 +2002,16 @@ en:
unchangable_error_message: "Predefined roles can not be changed!"
protocols:
print:
title: "Print protocol"
button: "Print"
modal:
title: "Print protocol"
content: "Select what to include in the printed version of this protocol."
include_comments: "Include comments when printing"
header:
printed_from: "Printed from"
print_info: "on %{datetime} by %{full_name}"
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>"

View file

@ -492,6 +492,7 @@ Rails.application.routes.draw do
resources :protocols, only: [:index, :edit, :create] do
resources :steps, only: [:new, :create]
member do
get 'print', to: 'protocols#print'
get 'linked_children', to: 'protocols#linked_children'
post 'linked_children_datatable',
to: 'protocols#linked_children_datatable'