Merge pull request #4755 from aignatov-bio/ai-sci-7590-update-protocol-screen-draft

Update protocol view screen [SCI-7590][SCI-7617]
This commit is contained in:
aignatov-bio 2023-02-13 10:58:03 +01:00 committed by GitHub
commit 65bf9b2511
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 299 additions and 136 deletions

View file

@ -9,38 +9,96 @@
margin: 0 -16px; margin: 0 -16px;
min-height: calc(100vh - var(--navbar-height)); min-height: calc(100vh - var(--navbar-height));
overflow: hidden; overflow: hidden;
padding: 36px 10px 10px; padding: 0 0 10px;
width: calc(100% + 31px); width: calc(100% + 31px);
.content-header {
padding: 0 2em;
}
.protocol-position-container { .protocol-position-container {
background-color: $color-white; background-color: $color-white;
box-shadow: $flyout-shadow; box-shadow: $flyout-shadow;
margin: 0 auto; margin: 20px auto;
max-width: 900px; max-width: 900px;
padding: 10px 10px 10px 26px; padding: 10px 10px 10px 26px;
} }
.protocol-section {
margin: 16px 0 16px -20px;
&.protocol-steps-section {
margin-left: 0;
}
.protocol-section-caret {
color: $color-volcano;
display: inline-block;
padding: .5em;
text-decoration: none;
.fas {
margin-right: 5px;
}
&:not(.collapsed) .fas {
@include rotate(90deg);
}
}
.protocol-section-title {
display: inline-block;
h2 {
display: inline-block;
margin: 10px 0;
}
.protocol-code {
color: $color-volcano;
margin-left: .5em;
}
}
.protocol-section-header {
align-items: center;
display: flex;
flex-wrap: wrap;
.actions-block {
display: flex;
flex-grow: 1;
justify-content: flex-end;
.caret {
margin-left: 25px;
}
}
}
.protocol-details {
padding-left: 20px;
}
}
.protocol-metadata { .protocol-metadata {
margin-bottom: 2em; margin-bottom: 2em;
.data-block {
margin-bottom: 16px;
}
.authors-data { .authors-data {
align-items: center; align-items: center;
display: flex; display: flex;
margin-top: -12px;
.authors-list { .authors-list {
flex-basis: calc(100% - 90px); flex-basis: calc(100% - 90px);
flex-grow: 1; flex-grow: 1;
margin-left: .75em; margin-left: .75em;
line-height: 32px;
&:hover:not(.editing) {
.sci-inline-edit__content {
border: $border-focus;
}
}
.sci-inline-edit__content {
padding-top: .35em;
}
} }
* { * {
@ -51,6 +109,7 @@
.keywords-data { .keywords-data {
align-items: center; align-items: center;
display: flex; display: flex;
margin-top: -12px;
.keywords-list { .keywords-list {
flex-basis: calc(100% - 90px); flex-basis: calc(100% - 90px);

View file

@ -78,6 +78,7 @@ class ProtocolsController < ApplicationController
only: %i(protocolsio_import_create protocolsio_import_save) only: %i(protocolsio_import_create protocolsio_import_save)
before_action :set_importer, only: %i(load_from_file import) before_action :set_importer, only: %i(load_from_file import)
before_action :set_inline_name_editing, only: :show
layout 'fluid' layout 'fluid'
@ -1103,6 +1104,18 @@ class ProtocolsController < ApplicationController
end end
end end
def set_inline_name_editing
return unless can_manage_protocol_in_repository?(@protocol)
@inline_editable_title_config = {
name: 'title',
params_group: 'protocol',
item_id: @protocol.id,
field_to_udpate: 'name',
path_to_update: name_protocol_path(@protocol)
}
end
def load_team_and_type def load_team_and_type
@current_team = current_team @current_team = current_team
# :public, :private or :archive # :public, :private or :archive

View file

@ -33,7 +33,7 @@
</div> </div>
<div v-if="protocol.id" id="protocol-content" class="protocol-content collapse in" aria-expanded="true"> <div v-if="protocol.id" id="protocol-content" class="protocol-content collapse in" aria-expanded="true">
<div class="protocol-description"> <div class="protocol-description">
<div class="protocol-name"> <div class="protocol-name" v-if="!inRepository">
<InlineEdit <InlineEdit
v-if="urls.update_protocol_name_url" v-if="urls.update_protocol_name_url"
:value="protocol.attributes.name" :value="protocol.attributes.name"
@ -48,6 +48,20 @@
</span> </span>
</div> </div>
<ProtocolMetadata v-if="protocol.attributes && protocol.attributes.in_repository" :protocol="protocol" @update="updateProtocol"/> <ProtocolMetadata v-if="protocol.attributes && protocol.attributes.in_repository" :protocol="protocol" @update="updateProtocol"/>
<div :class="inRepository ? 'protocol-section protocol-information' : ''">
<div v-if="inRepository" id="protocol-description" class="protocol-section-header">
<div class="protocol-description-container">
<a class="protocol-section-caret" role="button" data-toggle="collapse" href="#protocol-description-container" aria-expanded="false" aria-controls="protocol-description-container">
<i class="fas fa-caret-right"></i>
<span id="protocolDescriptionLabel" class="protocol-section-title">
<h2>
{{ i18n.t("protocols.header.protocol_description") }}
</h2>
</span>
</a>
</div>
</div>
<div id="protocol-description-container" :class=" inRepository ? 'protocol-description collapse in' : ''" >
<div v-if="urls.update_protocol_description_url"> <div v-if="urls.update_protocol_description_url">
<Tinymce <Tinymce
:value="protocol.attributes.description" :value="protocol.attributes.description"
@ -67,10 +81,22 @@
{{ i18n.t("protocols.no_text_placeholder") }} {{ i18n.t("protocols.no_text_placeholder") }}
</div> </div>
</div> </div>
<a v-if="urls.add_step_url && protocol.attributes.in_repository" class="btn btn-primary repository-new-step" @click="addStep(steps.length)"> </div>
<span class="fas fa-plus" aria-hidden="true"></span> </div>
<span>{{ i18n.t("protocols.steps.new_step") }}</span> <div :class="inRepository ? 'protocol-section protocol-steps-section protocol-information' : ''">
<div v-if="inRepository" id="protocol-steps" class="protocol-section-header">
<div class="protocol-steps-container">
<a class="protocol-section-caret" role="button" data-toggle="collapse" href="#protocol-steps-container" aria-expanded="false" aria-controls="protocol-steps-container">
<i class="fas fa-caret-right"></i>
<span id="protocolStepsLabel" class="protocol-section-title">
<h2>
{{ i18n.t("protocols.header.protocol_steps") }}
</h2>
</span>
</a> </a>
</div>
</div>
<div id="protocol-steps-container" :class=" inRepository ? 'protocol-steps collapse in' : ''">
<div v-if="steps.length > 0" class="protocol-step-actions"> <div v-if="steps.length > 0" class="protocol-step-actions">
<button class="btn btn-light" @click="collapseSteps" tabindex="0"> <button class="btn btn-light" @click="collapseSteps" tabindex="0">
<span class="fas fa-caret-up"></span> <span class="fas fa-caret-up"></span>
@ -110,11 +136,13 @@
</div> </div>
</template> </template>
</div> </div>
<button v-if="steps.length > 0 && urls.add_step_url" class="btn btn-primary" @click="addStep(steps.length)"> <button v-if="(steps.length > 0 || inRepository) && urls.add_step_url" :class="!inRepository ? 'btn btn-primary' : 'btn btn-secondary'" @click="addStep(steps.length)">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
{{ i18n.t("protocols.steps.new_step") }} {{ i18n.t("protocols.steps.new_step") }}
</button> </button>
</div> </div>
</div>
</div>
<ProtocolModals/> <ProtocolModals/>
<ReorderableItemsModal v-if="reordering" <ReorderableItemsModal v-if="reordering"
:title="i18n.t('protocols.reorder_steps.modal.title')" :title="i18n.t('protocols.reorder_steps.modal.title')"

View file

@ -1,23 +1,46 @@
<template> <template>
<div class="protocol-section protocol-information">
<div id="protocol-details" class="protocol-section-header">
<div class="protocol-details-container">
<a class="protocol-section-caret" role="button" data-toggle="collapse" href="#details-container" aria-expanded="false" aria-controls="details-container">
<i class="fas fa-caret-right"></i>
<span id="protocolDetailsLabel" class="protocol-section-title">
<h2>
{{ i18n.t("protocols.header.details") }}
</h2>
<span class="protocol-code" >{{ protocol.attributes.code }}</span>
</span>
</a>
</div>
<div class="actions-block">
<a class="btn btn-light icon-btn pull-right" data-toggle="modal" data-target="#print-protocol-modal" tabindex="0">
<span class="fas fa-print" aria-hidden="true"></span>
</a>
<button class="btn btn-light">{{ i18n.t("protocols.header.versions") }}</button>
<button v-if="!protocol.attributes.published" class="btn btn-primary">{{ i18n.t("protocols.header.publish") }}</button>
<button v-else class="btn btn-secondary">{{ i18n.t("protocols.header.save_as_draft") }}</button>
</div>
</div>
<div id="details-container" class="protocol-details collapse in">
<div class="protocol-metadata"> <div class="protocol-metadata">
<p class="data-block"> <p class="data-block">
<span class="fas block-icon fa-calendar-alt fa-fw"></span> {{ i18n.t("protocols.header.version") }}
<b>{{ protocol.attributes.version }}</b>
</p>
<p class="data-block">
{{ i18n.t("protocols.header.updated_at") }}
<b>{{ protocol.attributes.updated_at_formatted }}</b>
</p>
<p class="data-block">
{{ i18n.t("protocols.header.created_at") }} {{ i18n.t("protocols.header.created_at") }}
<b>{{ protocol.attributes.created_at_formatted }}</b> <b>{{ protocol.attributes.created_at_formatted }}</b>
</p> </p>
<p class="data-block"> <p class="data-block">
<span class="fas block-icon fa-user fa-fw"></span>
{{ i18n.t("protocols.header.added_by") }} {{ i18n.t("protocols.header.added_by") }}
<img :src="protocol.attributes.added_by.avatar"/> <img :src="protocol.attributes.added_by.avatar"/>
{{ protocol.attributes.added_by.name }} {{ protocol.attributes.added_by.name }}
</p> </p>
<p class="data-block">
<span class="fas block-icon fa-edit fa-fw"></span>
{{ i18n.t("protocols.header.updated_at") }}
<b>{{ protocol.attributes.updated_at_formatted }}</b>
</p>
<p class="data-block authors-data"> <p class="data-block authors-data">
<span class="fas block-icon fa-graduation-cap fa-fw"></span>
<span>{{ i18n.t("protocols.header.authors") }}</span> <span>{{ i18n.t("protocols.header.authors") }}</span>
<span class="authors-list" v-if="protocol.attributes.urls.update_protocol_authors_url"> <span class="authors-list" v-if="protocol.attributes.urls.update_protocol_authors_url">
<InlineEdit <InlineEdit
@ -33,7 +56,6 @@
</span> </span>
</p> </p>
<p class="data-block keywords-data"> <p class="data-block keywords-data">
<span class="fas block-icon fa-font fa-fw"></span>
<span>{{ i18n.t("protocols.header.keywords") }}</span> <span>{{ i18n.t("protocols.header.keywords") }}</span>
<span class="keywords-list"> <span class="keywords-list">
<DropdownSelector <DropdownSelector
@ -51,6 +73,8 @@
</span> </span>
</p> </p>
</div> </div>
</div>
</div>
</template> </template>
<script> <script>

View file

@ -86,6 +86,7 @@ Canaid::Permissions.register_for(Protocol) do
# protocol in repository: update, create/update/delete/reorder step, # protocol in repository: update, create/update/delete/reorder step,
# toggle private/public visibility, archive # toggle private/public visibility, archive
can :manage_protocol_in_repository do |user, protocol| can :manage_protocol_in_repository do |user, protocol|
protocol.protocol_type.in_repository_draft? &&
protocol.permission_granted?(user, ProtocolPermissions::MANAGE) protocol.permission_granted?(user, ProtocolPermissions::MANAGE)
end end

View file

@ -7,12 +7,21 @@ class ProtocolSerializer < ActiveModel::Serializer
include ActionView::Helpers::TextHelper include ActionView::Helpers::TextHelper
attributes :name, :id, :urls, :description, :description_view, :updated_at, :in_repository, attributes :name, :id, :urls, :description, :description_view, :updated_at, :in_repository,
:created_at_formatted, :updated_at_formatted, :added_by, :authors, :keywords :created_at_formatted, :updated_at_formatted, :added_by, :authors, :keywords, :version, :code,
:published
def updated_at def updated_at
object.updated_at.to_i object.updated_at.to_i
end end
def version
object.in_repository_draft? ? I18n.t('protocols.draft') : object.version_number
end
def published
object.in_repository_published?
end
def added_by def added_by
{ {
avatar: object.added_by&.avatar_url(:icon_small), avatar: object.added_by&.avatar_url(:icon_small),

View file

@ -2,14 +2,34 @@
<%= content_for :sidebar do %> <%= content_for :sidebar do %>
<%= render partial: "/shared/sidebar/templates_sidebar", locals: {active: :protocol} %> <%= render partial: "/shared/sidebar/templates_sidebar", locals: {active: :protocol} %>
<% end %> <% end %>
<% provide(:container_class, 'no-second-nav-container') %>
<div class="content-pane protocols-show" > <div class="content-pane protocols-show" >
<div class="protocol-position-container"> <div class="content-header">
<div class="protocol-actions"> <div id="breadcrumbsWrapper">
<a class="btn btn-secondary pull-right" href="<%= print_protocol_path(@protocol) %>" target="_blank" tabindex="0"> <div class="breadcrumbs-container">
<span class="fas fa-print" aria-hidden="true"></span> <a href="<%= protocols_path %>" class="breadcrumbs-link">
<span><%= t("protocols.print.button") %></span> <%= t('sidebar.templates.protocol_templates') %>
</a> </a>
<span class="delimiter">/</span>
</div> </div>
</div>
<div class="title-row">
<h1>
<% if @inline_editable_title_config.present? %>
<%= render partial: "shared/inline_editing",
locals: {
initial_value: @protocol.name,
config: @inline_editable_title_config
} %>
<% else %>
<div class="name-readonly-placeholder">
<%= @protocol.name %>
</div>
<% end %>
</h1>
</div>
</div>
<div class="protocol-position-container">
<div <div
id="protocolContainer" id="protocolContainer"
data-protocol-url="<%= protocol_path(@protocol) %>" data-protocol-url="<%= protocol_path(@protocol) %>"

View file

@ -2427,6 +2427,7 @@ en:
unchangable_error_message: "Predefined roles can not be changed!" unchangable_error_message: "Predefined roles can not be changed!"
protocols: protocols:
draft: "Draft"
no_text_placeholder: 'No protocol description' no_text_placeholder: 'No protocol description'
reorder_steps: reorder_steps:
button: "Rearrange steps" button: "Rearrange steps"
@ -2530,6 +2531,14 @@ en:
row_success: "Exported" row_success: "Exported"
row_failed: "Failed" row_failed: "Failed"
header: header:
details: 'Details'
versions: 'Versions'
protocol_description: 'Protocol description'
protocol_steps: 'Protocol steps'
publish: 'Publish'
save_as_draft: 'Save as draft'
version: "Version:"
draft: 'Draft'
created_at: "Created at:" created_at: "Created at:"
updated_at: "Last modified at:" updated_at: "Last modified at:"
added_by: "Added by:" added_by: "Added by:"

View file

@ -556,7 +556,7 @@ Rails.application.routes.draw do
get 'versions_modal', to: 'protocols#versions_modal' get 'versions_modal', to: 'protocols#versions_modal'
get 'preview', to: 'protocols#preview' get 'preview', to: 'protocols#preview'
patch 'description', to: 'protocols#update_description' patch 'description', to: 'protocols#update_description'
patch 'name', to: 'protocols#update_name' put 'name', to: 'protocols#update_name'
patch 'authors', to: 'protocols#update_authors' patch 'authors', to: 'protocols#update_authors'
patch 'keywords', to: 'protocols#update_keywords' patch 'keywords', to: 'protocols#update_keywords'
post 'clone', to: 'protocols#clone' post 'clone', to: 'protocols#clone'