Merge pull request #4699 from scinote-eln/features/exposed_ids

Features/exposed ids
This commit is contained in:
artoscinote 2022-12-08 15:58:43 +01:00 committed by GitHub
commit 08b9ec24f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 459 additions and 113 deletions

View file

@ -5,11 +5,18 @@ var DasboardRecentWorkWidget = (function() {
function renderRecentWorkItem(data, container) {
$.each(data, (i, item) => {
var recentWorkItem = $($('#recent-work-item-template').html());
var recentWorkItemType = recentWorkItem.find('.object-type span');
recentWorkItem.attr('href', item.url);
recentWorkItem.find('.object-name').html(item.name);
recentWorkItem.find('.object-type').html(I18n.t('dashboard.recent_work.subject_type.' + item.subject_type));
recentWorkItemType.html(item.code || item.type);
recentWorkItem.find('.object-changed').html(item.last_change);
container.append(recentWorkItem);
if (item.code) {
recentWorkItemType.attr('data-toggle', 'tooltip');
recentWorkItemType.attr('title', `${item.type} ID: ${item.code}`);
recentWorkItemType.tooltip();
}
});
}

View file

@ -1127,7 +1127,7 @@ function updateModuleHtml(module, id, name, gridDistX, gridDistY) {
module.find(".panel-title").html(name);
module.find(".ep").html($("#drag-connections-placeholder").text().trim());
module.find(".ep").html($("#drag-connections-placeholder").html());
// Add dropdown
var dropdown = document.createElement("div");

View file

@ -519,7 +519,7 @@ var ProjectsIndex = (function() {
$(projectsPageSelector)
.on('ajax:success', '.change-projects-view-type-form', function(ev, data) {
$(cardsWrapper).removeClass('list').addClass(data.cards_view_type_class);
$(cardsWrapper).removeClass('list cards').addClass(data.cards_view_type_class);
$(projectsPageSelector).find('.cards-switch .button-to').removeClass('selected');
$(ev.target).find('.button-to').addClass('selected');
$(ev.target).parents('.dropdown.view-switch').removeClass('open');

View file

@ -55,7 +55,7 @@
function initProjectsViewModeSwitch() {
$(experimentsPage)
.on('ajax:success', '.change-experiments-view-type-form', function(ev, data) {
$(cardsWrapper).removeClass('list').addClass(data.cards_view_type_class);
$(cardsWrapper).removeClass('list cards').addClass(data.cards_view_type_class);
$(experimentsPage).find('.cards-switch .button-to').removeClass('selected');
$(ev.target).find('.button-to').addClass('selected');
$(ev.target).parents('.dropdown.view-switch').removeClass('open');

View file

@ -53,7 +53,7 @@ function initProtocolsTable() {
</div>`;
}
}, {
targets: [ 1, 2, 3, 4, 5 ],
targets: [ 1, 2, 3, 4, 5, 6 ],
searchable: true,
orderable: true
}],
@ -61,13 +61,14 @@ function initProtocolsTable() {
{ data: "0" },
{ data: "1" },
{ data: "2" },
{ data: "3" },
{
data: "3",
data: "4",
visible: repositoryType != "archive"
},
{ data: "4" },
{ data: "5" },
{ data: "6" }
{ data: "6" },
{ data: "7" }
],
oLanguage: {
sSearch: I18n.t('general.filter')

View file

@ -135,7 +135,7 @@
if (data.archived) {
$(row).addClass('archived');
}
if (data['3'].processing || data['4'].processing) {
if (data['4'].processing || data['5'].processing) {
$(row).addClass('processing');
}
}
@ -225,7 +225,7 @@
var $table = $('#reports-table');
REPORTS_TABLE = $table.DataTable({
dom: "Rt<'pagination-row hidden'<'pagination-info'li><'pagination-actions'p>>",
order: [[8, 'desc']],
order: [[9, 'desc']],
sScrollX: '100%',
sScrollXInner: '100%',
processing: true,
@ -244,13 +244,13 @@
render: renderCheckboxHTML
},
{
targets: 3,
targets: 4,
searchable: false,
sWidth: '60',
render: renderPdfFile
},
{
targets: 4,
targets: 5,
searchable: false,
sWidth: '60',
render: renderDocxFile

View file

@ -53,7 +53,7 @@
grid-row: span 7;
.experiment-code-cell {
display: none;
display: block;
}
&.experiment-card {
@ -93,6 +93,8 @@
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
position: relative;
a {
color: inherit;
@ -534,3 +536,33 @@
}
}
}
.cards-wrapper.last-page.cards {
.experiment-card {
.experiment-name-cell {
right: 28px;
top: -11px;
}
.data-row {
.card-label {
color: $color-silver-chalice;
}
}
.modified-date-cell {
color: $color-silver-chalice;
left: 80px;
margin-left: auto;
margin-right: 114px;
position: relative;
top: -2px;
}
.experiment-code-cell {
left: 20px;
position: relative;
top: 5px;
}
}
}

View file

@ -61,6 +61,20 @@
word-break: break-all;
word-wrap: break-word;
}
.task-card-code {
bottom: 5px;
color: $color-volcano;
font-weight: 400;
position: absolute;
right: 5px;
}
}
.archived-task-card-code {
bottom: 30px;
position: absolute;
right: 25px;
}
// Create wopi file

View file

@ -93,7 +93,7 @@
.repositories-dropdown-menu {
max-height: 250px;
overflow: auto;
.repository {
@include font-button;
cursor: pointer;
@ -420,9 +420,29 @@
max-width: 100vw;
width: 650px;
.dropdown-header,
.dropdown-body {
padding: 10px 32px;
}
.dropdown-header {
background: $color-white;
border-bottom: $border-tertiary;
.protocol-name {
color: $color-black;
margin-top: 0;
}
.protocol-header-info {
color: $color-black;
font-size: .875em;
font-weight: 400;
}
}
.dropdown-body {
border-bottom: $border-tertiary;
padding: 10px 32px;
.info-line {
align-items: center;
@ -647,3 +667,8 @@
}
}
}
.task-details-code {
display: inline-block;
margin-left: 4px;
}

View file

@ -192,12 +192,24 @@ path, ._jsPlumb_endpoint {
left: 0;
}
}
.panel-body {
height: 90px;
}
.ep {
font-style: italic;
.task-card-code {
color: $color-volcano;
font-style: normal;
font-weight: 400;
margin-bottom: 4px;
.new-my-module-canvas {
color: $color-silver-chalice;
}
}
}
.dropdown {
@ -689,18 +701,13 @@ li.module-hover {
.project-name-cell {
align-items: center;
display: flex;
height: 2em;
margin: 0 1.75em;
overflow: hidden;
a {
color: inherit;
overflow: hidden;
white-space: nowrap;
}
.name {
line-height: 2em;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
@ -854,7 +861,7 @@ li.module-hover {
}
&.list {
grid-template-columns: max-content repeat(calc(var(--list-columns-number) - 3), minmax(100px, auto)) max-content max-content;
grid-template-columns: max-content repeat(calc(var(--list-columns-number) - 2), minmax(100px, auto)) max-content max-content;
.projects-group {
display: contents;
@ -902,7 +909,7 @@ li.module-hover {
}
.name {
grid-column: 5 span;
grid-column: 6 span;
line-height: 3em;
&:before {
@ -932,22 +939,28 @@ li.module-hover {
}
}
.start-date-cell {
.project-code-cell {
display: flex;
align-items: center;
grid-column: 3;
}
.visibility-cell {
.start-date-cell {
grid-column: 4;
}
.user-cell {
.visibility-cell {
grid-column: 5;
}
.user-cell {
grid-column: 6;
}
.actions-cell {
align-items: center;
display: flex;
grid-column: 6;
grid-column: 7;
position: initial;
}
}
@ -1017,6 +1030,7 @@ li.module-hover {
display: none !important;
}
.projects-container {
.project-actions-menu {
.btn-light:hover {
@ -1027,6 +1041,56 @@ li.module-hover {
.cards-wrapper {
grid-auto-rows: 2.5em;
.visibility-cell {
.value {
color: $color-black;
}
}
.start-date-cell {
.value {
color: $color-black;
}
}
.archived-date-cell {
.value {
color: $color-black;
}
}
&.last-page.cards {
.project-card {
.start-date-cell {
top: 36px;
.value {
color: $color-black;
}
}
.archived-date-cell {
top: 26px;
.value {
color: $color-black;
}
}
.visibility-cell {
top: 16px;
.value {
color: $color-black;
}
}
.user-cell {
top: 6px;
}
}
}
.card.project-card {
.data-row {
color: $color-silver-chalice;
@ -1046,23 +1110,23 @@ li.module-hover {
}
&.list {
--list-columns-number: 7;
--list-columns-number: 8;
grid-auto-rows: 3em 1px;
grid-template-columns: max-content repeat(calc(var(--list-columns-number) - 2), minmax(100px, auto)) max-content;
.card {
&.folder-card {
.name {
grid-column: 6 span;
grid-column: 7 span;
}
}
.archived-date-cell {
grid-column: 6;
grid-column: 7;
}
.actions-cell {
grid-column: 7;
grid-column: 8;
position: initial;
}
}
@ -1082,3 +1146,58 @@ li.module-hover {
margin: 1em 0;
}
}
.cards-wrapper.cards {
grid-gap: 25px;
.project-card {
.project-name-cell {
align-items: start !important;
top: 12%;
min-height: 35px;
position: absolute;
left: 14px;
top: 42px;
a {
color: inherit;
}
.name {
-webkit-box-orient: vertical;
display: -webkit-box;
-webkit-line-clamp: 2;
max-width: 200px;
overflow: hidden;
}
}
.project-code-cell {
height: min-content;
margin-top: 5px;
padding-left: 20px;
position: relative;
}
.data-row {
position: relative;
top: 5%;
.card-label {
color: #808080 !important;
}
&.start-date-cell {
top: 30px;
}
&.visibility-cell {
top: 18px;
}
&.user-cell {
top: 5px;
}
}
}
}

View file

@ -23,6 +23,7 @@ class ProtocolsDatatable < CustomDatatable
def sortable_columns
@sortable_columns ||= [
"Protocol.name",
"Protocol.id",
"protocol_keywords_str",
"Protocol.nr_of_linked_children",
"full_username_str",
@ -34,6 +35,7 @@ class ProtocolsDatatable < CustomDatatable
def searchable_columns
@searchable_columns ||= [
"Protocol.name",
"Protocol.#{Protocol::PREFIXED_ID_SQL}",
timestamp_db_column,
"Protocol.updated_at"
]
@ -56,9 +58,11 @@ class ProtocolsDatatable < CustomDatatable
# now the method checks if the column is the created_at or updated_at and generate a custom SQL to parse
# it back to the caller method
def new_search_condition(column, value)
model, column = column.split('.')
model, column = column.split('.', 2)
model = model.constantize
case column
when Protocol::PREFIXED_ID_SQL
casted_column = ::Arel::Nodes::SqlLiteral.new(Protocol::PREFIXED_ID_SQL)
when 'published_on'
casted_column = ::Arel::Nodes::NamedFunction.new('CAST',
[ Arel.sql("to_char( protocols.created_at, '#{ formated_date }' ) AS VARCHAR") ] )
@ -97,11 +101,12 @@ class ProtocolsDatatable < CustomDatatable
else
name_html(record)
end,
'2': keywords_html(record),
'3': modules_html(record),
'4': escape_input(record.full_username_str),
'5': timestamp_column_html(record),
'6': I18n.l(record.updated_at, format: :full)
'2': escape_input(record.code),
'3': keywords_html(record),
'4': modules_html(record),
'5': escape_input(record.full_username_str),
'6': timestamp_column_html(record),
'7': I18n.l(record.updated_at, format: :full)
}
end
result_data

View file

@ -7,6 +7,7 @@ class ReportDatatable < CustomDatatable
TABLE_COLUMNS = %w(
Report.project_name
Report.name
Report.code
Report.pdf_file
Report.docx_file
Report.created_by_name
@ -40,6 +41,9 @@ class ReportDatatable < CustomDatatable
records.left_joins(:pdf_file_attachment)
.order(active_storage_attachments: sort_direction(order_params))
.order(pdf_file_status: sort_direction(order_params) == 'ASC' ? :desc : :asc)
when 'reports.code'
sort_by = "reports.id #{sort_direction(order_params)}"
records.order(sort_by)
else
sort_by = "#{sort_column(order_params)} #{sort_direction(order_params)}"
records.order(sort_by)
@ -54,12 +58,13 @@ class ReportDatatable < CustomDatatable
'0' => record.id,
'1' => sanitize_input(record.project_name),
'2' => sanitize_input(record.name),
'3' => pdf_file(record),
'4' => docx_file(record),
'5' => sanitize_input(record.created_by_name),
'6' => sanitize_input(record.modified_by_name),
'7' => I18n.l(record.created_at, format: :full),
'8' => I18n.l(record.updated_at, format: :full),
'3' => sanitize_input(record.code),
'4' => pdf_file(record),
'5' => docx_file(record),
'6' => sanitize_input(record.created_by_name),
'7' => sanitize_input(record.modified_by_name),
'8' => I18n.l(record.created_at, format: :full),
'9' => I18n.l(record.updated_at, format: :full),
'archived' => record.project.archived?,
'edit' => edit_project_report_path(record.project_id, record.id),
'status' => status_project_report_path(record.project_id, record.id),
@ -106,7 +111,7 @@ class ReportDatatable < CustomDatatable
def filter_records(records)
records.where_attributes_like(
['project_name', 'reports.name', 'reports.description'],
['project_name', 'reports.name', 'reports.description', "('RP' || reports.id)"],
dt_params.dig(:search, :value)
)
end

View file

@ -2,6 +2,6 @@
module CardsViewHelper
def cards_view_type_class(view_type)
view_type == 'table' ? 'list' : ''
view_type == 'table' ? 'list' : 'cards'
end
end

View file

@ -48,6 +48,10 @@ module ProjectsHelper
records.sort_by { |c| c.name.downcase }
when 'ztoa'
records.sort_by { |c| c.name.downcase }.reverse!
when 'id_asc'
records.sort_by(&:id)
when 'id_desc'
records.sort_by(&:id).reverse!
when 'archived_old'
records.sort_by(&:archived_on)
when 'archived_new'

View file

@ -1,7 +1,9 @@
# frozen_string_literal: true
class MyModule < ApplicationRecord
SEARCHABLE_ATTRIBUTES = ['my_modules.name', 'my_modules.description']
ID_PREFIX = 'TA'
include PrefixedIdModel
SEARCHABLE_ATTRIBUTES = ['my_modules.name', 'my_modules.description', PREFIXED_ID_SQL].freeze
include ArchivableModel
include SearchableModel
@ -10,6 +12,9 @@ class MyModule < ApplicationRecord
include PermissionCheckableModel
include Assignable
ID_PREFIX = 'TA'
include PrefixedIdModel
attr_accessor :transition_error_rollback
enum state: Extends::TASKS_STATES

View file

@ -1,4 +1,10 @@
# frozen_string_literal: true
class Project < ApplicationRecord
ID_PREFIX = 'PR'
include PrefixedIdModel
SEARCHABLE_ATTRIBUTES = ['projects.name', PREFIXED_ID_SQL].freeze
include ArchivableModel
include SearchableModel
include SearchableByNameModel
@ -80,7 +86,7 @@ class Project < ApplicationRecord
)
new_query = Project.viewable_by_user(user, current_team || user.teams)
.where_attributes_like('projects.name', query, options)
.where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
new_query = new_query.active unless include_archived
# Show all results if needed
@ -127,8 +133,8 @@ class Project < ApplicationRecord
def validate_view_state(view_state)
if %w(cards table).exclude?(view_state.state.dig('experiments', 'view_type')) ||
%w(new old atoz ztoa).exclude?(view_state.state.dig('experiments', 'active', 'sort')) ||
%w(new old atoz ztoa archived_new archived_old).exclude?(view_state.state.dig('experiments', 'archived', 'sort'))
%w(new old atoz ztoa id_asc id_desc).exclude?(view_state.state.dig('experiments', 'active', 'sort')) ||
%w(new old atoz ztoa id_asc id_desc archived_new archived_old).exclude?(view_state.state.dig('experiments', 'archived', 'sort'))
view_state.errors.add(:state, :wrong_state)
end
end
@ -171,6 +177,8 @@ class Project < ApplicationRecord
when 'old' then { created_at: :asc }
when 'atoz' then { name: :asc }
when 'ztoa' then { name: :desc }
when 'id_asc' then { id: :asc }
when 'id_desc' then { id: :desc }
when 'archived_new' then { archived_on: :desc }
when 'archived_old' then { archived_on: :asc }
else { created_at: :desc }

View file

@ -1,6 +1,11 @@
# frozen_string_literal: true
class Protocol < ApplicationRecord
ID_PREFIX = 'PT'
include PrefixedIdModel
SEARCHABLE_ATTRIBUTES = ['protocols.name', 'protocols.description',
'protocols.authors', 'protocol_keywords.name', PREFIXED_ID_SQL].freeze
include SearchableModel
include RenamingUtil
include SearchableByNameModel
@ -180,15 +185,7 @@ class Protocol < ApplicationRecord
.joins('LEFT JOIN protocol_keywords ' \
'ON protocol_keywords.id = ' \
'protocol_protocol_keywords.protocol_keyword_id')
.where_attributes_like(
[
'protocols.name',
'protocols.description',
'protocols.authors',
'protocol_keywords.name'
],
query, options
)
.where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
# Show all results if needed
if page == Constants::SEARCH_NO_LIMIT

View file

@ -1,6 +1,10 @@
# frozen_string_literal: true
class Report < ApplicationRecord
ID_PREFIX = 'RP'
include PrefixedIdModel
SEARCHABLE_ATTRIBUTES = ['reports.name', 'reports.description', PREFIXED_ID_SQL].freeze
include SettingsModel
include Assignable
include PermissionCheckableModel
@ -74,7 +78,7 @@ class Report < ApplicationRecord
new_query = Report.distinct
.where(reports: { project_id: project_ids })
.where_attributes_like(%i(name description), query, options)
.where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
# Show all results if needed
if page == Constants::SEARCH_NO_LIMIT

View file

@ -84,8 +84,8 @@ class Team < ApplicationRecord
end
def validate_view_state(view_state)
if %w(new old atoz ztoa).exclude?(view_state.state.dig('projects', 'active', 'sort')) ||
%w(new old atoz ztoa archived_new archived_old).exclude?(view_state.state.dig('projects', 'archived', 'sort')) ||
if %w(new old atoz ztoa id_asc id_desc).exclude?(view_state.state.dig('projects', 'active', 'sort')) ||
%w(new old atoz ztoa id_asc id_desc archived_new archived_old).exclude?(view_state.state.dig('projects', 'archived', 'sort')) ||
%w(cards table).exclude?(view_state.state.dig('projects', 'view_type'))
view_state.errors.add(:state, :wrong_state)
end

View file

@ -93,10 +93,11 @@ module Dashboard
ordered_query = Activity.from("(#{query.to_sql}) AS activities").where.not(group_id: nil)
.select(:group_id,
:subject_id,
:name,
'MAX(last_change) AS last_change',
'MAX(report_project_id) AS report_project_id')
.group(:group_id, :name)
.group(:group_id, :subject_id, :name)
.order('MAX(last_change) DESC').limit(Constants::SEARCH_LIMIT)
query_filter = "(group_id LIKE 'tsk%' OR group_id LIKE 'exp%' OR group_id LIKE 'pro%')" if @mode == 'projects'
@ -106,6 +107,7 @@ module Dashboard
ordered_query = ordered_query.where(query_filter) unless @mode == 'all'
recent_objects = ordered_query.as_json.map do |recent_object|
object_class = override_subject_type(recent_object).constantize
recent_object.deep_symbolize_keys!
recent_object.delete_if { |_k, v| v.nil? }
@ -115,6 +117,10 @@ module Dashboard
)
recent_object[:subject_type] = override_subject_type(recent_object)
recent_object[:name] = escape_input(recent_object[:name])
recent_object[:type] = I18n.t("activerecord.models.#{object_class.name.underscore}")
if object_class.include?(PrefixedIdModel)
recent_object[:code] = object_class::ID_PREFIX + recent_object[:subject_id].to_s
end
recent_object[:url] = generate_url(recent_object)
recent_object
end
@ -231,7 +237,7 @@ module Dashboard
end
def generate_url(recent_object)
object_id = recent_object[:group_id].gsub(/[^0-9]/, '')
object_id = recent_object.with_indifferent_access[:group_id].gsub(/[^0-9]/, '')
case recent_object[:subject_type]
when 'MyModule'
@ -250,17 +256,19 @@ module Dashboard
end
def override_subject_type(recent_object)
if recent_object[:group_id].include?('pro')
group_id = recent_object.with_indifferent_access[:group_id]
if group_id.include?('pro')
'Project'
elsif recent_object[:group_id].include?('exp')
elsif group_id.include?('exp')
'Experiment'
elsif recent_object[:group_id].include?('tsk')
elsif group_id.include?('tsk')
'MyModule'
elsif recent_object[:group_id].include?('prt')
elsif group_id.include?('prt')
'Protocol'
elsif recent_object[:group_id].include?('inv')
elsif group_id.include?('inv')
'RepositoryBase'
elsif recent_object[:group_id].include?('rpt')
elsif group_id.include?('rpt')
'Report'
end
end

View file

@ -15,7 +15,7 @@ class ExperimentsOverviewService
# Update sort if changed
@sort = @view_state.state.dig('experiments', @view_mode, 'sort') || 'atoz'
if @params[:sort] && @sort != @params[:sort] &&
%w(new old atoz ztoa archived_old archived_new).include?(@params[:sort])
%w(new old atoz ztoa id_asc id_desc archived_old archived_new).include?(@params[:sort])
@view_state.state['experiments'].merge!(Hash[@view_mode, { 'sort': @params[:sort] }.stringify_keys])
@view_state.save!
@sort = @view_state.state.dig('experiments', @view_mode, 'sort')
@ -85,6 +85,10 @@ class ExperimentsOverviewService
records.order(:name)
when 'ztoa'
records.order(name: :desc)
when 'id_asc'
records.order(id: :asc)
when 'id_desc'
records.order(id: :desc)
when 'archived_old'
records.group('projects.archived_on')
.order(Arel.sql('COALESCE(experiments.archived_on, projects.archived_on) ASC'))

View file

@ -16,7 +16,7 @@ class ProjectsOverviewService
# Update sort if chanhed
@sort = @view_state.state.dig('projects', @view_mode, 'sort') || 'atoz'
if @params[:sort] && @sort != @params[:sort] &&
%w(new old atoz ztoa archived_old archived_new).include?(@params[:sort])
%w(new old atoz ztoa id_asc id_desc archived_old archived_new).include?(@params[:sort])
@view_state.state['projects'].merge!(Hash[@view_mode, { 'sort': @params[:sort] }.stringify_keys])
@view_state.save!
@sort = @view_state.state.dig('projects', @view_mode, 'sort')
@ -140,6 +140,10 @@ class ProjectsOverviewService
records.order(:name)
when 'ztoa'
records.order(name: :desc)
when 'id_asc'
records.order(id: :asc)
when 'id_desc'
records.order(id: :desc)
when 'archived_old'
records.order(archived_on: :asc)
when 'archived_new'
@ -159,6 +163,10 @@ class ProjectsOverviewService
records.sort_by { |c| c.name.downcase }
when 'ztoa'
records.sort_by { |c| c.name.downcase }.reverse!
when 'id_asc'
records.sort_by(&:id)
when 'id_desc'
records.sort_by(&:id).reverse!
when 'archived_old'
records.sort_by(&:archived_on)
when 'archived_new'

View file

@ -16,7 +16,7 @@ module Reports::Docx::DrawMyModule
end
@docx.p do
text I18n.t('projects.reports.elements.module.user_time',
text I18n.t('projects.reports.elements.module.user_time', code: my_module.code,
timestamp: I18n.l(my_module.created_at, format: :full)), color: color[:gray]
if my_module.archived?
text ' | '

View file

@ -12,7 +12,7 @@ module Reports::Docx::DrawMyModuleProtocol
end
if @settings.dig('task', 'protocol', 'description') && protocol.description.present?
@docx.p I18n.t('projects.reports.elements.module.protocol.user_time',
@docx.p I18n.t('projects.reports.elements.module.protocol.user_time', code: protocol.code,
timestamp: I18n.l(protocol.created_at, format: :full)), color: @color[:gray]
html = custom_auto_link(protocol.description, team: @report_team)
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,

View file

@ -16,7 +16,7 @@ module Reports::Docx::DrawProjectHeader
end
@docx.p do
text I18n.t('projects.reports.elements.project_header.user_time',
text I18n.t('projects.reports.elements.project_header.user_time', code: project.code,
timestamp: I18n.l(project.created_at, format: :full)), color: color[:gray]
br
br

View file

@ -67,6 +67,9 @@
<%=t "experiments.canvas.edit.delete_module_group" %>
</span>
<span style="display: none;" id="drag-connections-placeholder">
<div class="task-card-code">
<%=t "experiments.canvas.edit.id" %> <span class="new-my-module-canvas"><%=t "experiments.canvas.edit.no_module_id" %></span>
</div>
<%=t "experiments.canvas.edit.drag_connections" %>
</span>
</div>

View file

@ -21,6 +21,9 @@
</div>
<div class="panel-body ep">
<div class="task-card-code">
<%=t "experiments.canvas.edit.id" %> <%= my_module.code %>
</div>
<%= t('experiments.canvas.edit.drag_connections') %>
</div>

View file

@ -114,5 +114,9 @@
<div role="tabpanel" class="tab-pane" id="<%= my_module.id %>_activities" data-contents="activities"></div>
<div role="tabpanel" class="tab-pane" id="<%= my_module.id %>_comments" data-contents="comments"></div>
</div>
<div class="task-card-code">
ID: <%= my_module.code %>
</div>
</div>
</div>

View file

@ -19,7 +19,7 @@
<template id="recent-work-item-template">
<a href="" class="recent-work-item">
<div class="object-name"></div>
<div class="object-type"></div>
<div class="object-type"><span data-placement="bottom"></span></div>
<div class="object-changed"></div>
</a>
</template>

View file

@ -1,7 +1,11 @@
<% task_date = current_task_date(task) %>
<a class="current-task-item" href="<%= protocols_my_module_path(task.id) %>">
<div class="current-task-breadcrumbs"><%= task.experiment.project.name %>
<span class="slash">/</span><%= task.experiment.name %></div>
<span class="slash">/</span>
<%= task.experiment.name %>
<span class="slash">/</span>
<%= task.code %>
</div>
<div class="task-name row-border">
<%= task.name %>
</div>

View file

@ -67,6 +67,9 @@
<%= render partial: "module_header_details_popover.html.erb" %>
</div>
</span>
<span class="task-details-code">
<%= @my_module.code %>
</span>
</div>
</div>
<div id="details-container" class="task-details collapse">

View file

@ -15,6 +15,14 @@
<i class="fas fa-info-circle"></i>
</a>
<div class="dropdown-menu status-info-dropdown" aria-labelledby="my-module-protocol-info-button">
<div class="dropdown-header">
<h2 class="protocol-name">
<%= @protocol.parent&.name || @protocol.name %>
</h2>
<div class="protocol-header-info">
<span>ID: <%= @protocol.code %></span>
</div>
</div>
<div class="dropdown-body">
<div class="info-line">
<div class="description"><%= t("my_modules.protocols.protocol_status_bar.protocol_created") %></div>

View file

@ -28,6 +28,7 @@
</div>
</div>
<div class="table-header-cell"><%= t('.card.name') %></div>
<div class="table-header-cell"><%= t('.card.id') %></div>
<div class="table-header-cell"><%= t('.card.start_date') %></div>
<div class="table-header-cell"><%= t('.card.visibility') %></div>
<div class="table-header-cell"><%= t('.card.users') %></div>

View file

@ -88,9 +88,9 @@
<span><i class="fas fa-sort-amount-down"></i></span>
</button>
<ul id="sortMenuDropdown" class="dropdown-menu sort-projects-menu dropdown-menu-right" aria-labelledby="sortMenu">
<% %w(new old atoz ztoa archived_new archived_old).each_with_index do |sort, i| %>
<% %w(new old atoz ztoa id_asc id_desc archived_new archived_old).each_with_index do |sort, i| %>
<% if i.even? && i.positive? %>
<li class="divider" <%= i > 3 ? 'data-view-mode=archived' : '' %>></li>
<li class="divider" <%= i > 5 ? 'data-view-mode=archived' : '' %>></li>
<% end %>
<li <%= %w(archived_new archived_old).include?(sort) ? 'data-view-mode=archived' : '' %>>
<a class="<%= 'selected' if @current_sort == sort %>"

View file

@ -8,6 +8,10 @@
<span class="sci-checkbox-label"></span>
</div>
</div>
<div class="project-code-cell table-cell">
<span><%= project.code %></span>
</div>
<div class="project-name-cell table-cell">
<% if project.archived? %>
<%= link_to project_url(project, view_mode: :archived) do %>
@ -40,6 +44,14 @@
<span class="value cell-value"> <%= l(project.created_at, format: :full_with_comma) %></span>
</div>
<% if project.archived? %>
<div class="data-row archived-date-cell table-cell">
<span class="card-label"><%= t('projects.index.card.archived_date') %></span>
<span class="value card-value"> <%= l(project.archived_on, format: :full_date) %></span>
<span class="value cell-value"> <%= l(project.archived_on, format: :full_with_comma) %></span>
</div>
<% end %>
<div class="data-row visibility-cell table-cell">
<span class="card-label"><%= t('projects.index.card.visibility') %></span>
<span class="value">
@ -68,12 +80,4 @@
<% end %>
</div>
</div>
<% if project.archived? %>
<div class="data-row archived-date-cell table-cell">
<span class="card-label"><%= t('projects.index.card.archived_date') %></span>
<span class="value card-value"> <%= l(project.archived_on, format: :full_date) %></span>
<span class="value cell-value"> <%= l(project.archived_on, format: :full_with_comma) %></span>
</div>
<% end %>
</div>

View file

@ -8,7 +8,16 @@
<span class="sci-checkbox-label"></span>
</div>
</div>
<div class="experiment-code-cell table-cell">
<span><%= experiment.code %></span>
</div>
<div class="data-row modified-date-cell table-cell">
<span class="card-label" cards-render="true"><%= t('experiments.card.modified_date') %></span>
<span class="card-value"><%= l(experiment.updated_at, format: :full_date) %></span>
</div>
<div class="experiment-name-cell table-cell">
<div class="workflow-img-wrapper" list-render="true">
<%= render partial: 'projects/show/experiment_workflow_image_container', locals: { experiment: experiment } %>
@ -19,9 +28,6 @@
<%= link_to experiment.name, canvas_experiment_path(experiment), title: experiment.name, class: 'name-link' %>
<% end %>
</div>
<div class="experiment-code-cell table-cell">
<span><%= experiment.code %></span>
</div>
<div class="actions actions-cell table-cell">
<div class="dropdown dropdown-async experiment-actions-menu" data-dropdown-url="<%= actions_dropdown_experiment_path(experiment) %>">
<button class="btn btn-light dropdown-toggle icon-btn" type="button" id="experimentActionsDropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
@ -36,17 +42,14 @@
<span class="card-label" cards-render="true"><%= t('experiments.card.start_date') %></span>
<span class="card-value"><%= l(experiment.created_at, format: :full_date) %></span>
</div>
<div class="data-row modified-date-cell table-cell">
<span class="card-label" cards-render="true"><%= t('experiments.card.modified_date') %></span>
<span class="card-value"><%= l(experiment.updated_at, format: :full_date) %></span>
</div>
<% if experiment.archived_branch? %>
<div class="data-row archived-date-cell table-cell">
<span class="card-label" cards-render="true"><%= t('experiments.card.archived_date') %></span>
<span class="card-value"><%= l(experiment.archived_on || project.archived_on, format: :full_date) %></span>
</div>
<% end %>
<div class="data-row" cards-render="true" data-view-mode="active">
<div class="data-row" cards-render="true">
<span class="card-label"><%= t('experiments.card.completed_task') %></span>
<span class="card-value"><%= t('experiments.card.completed_value', completed: experiment.completed_task_count, all: experiment.task_count) %></span>
</div>

View file

@ -1,8 +1,4 @@
<% if experiment.archived_branch? %>
<div class="archived-icon-plceholder">
<i class="fas fa-archive"></i>
</div>
<% elsif experiment.my_modules.any?(&:active?) %>
<% if experiment.my_modules.any?(&:active?) %>
<% if experiment.workflowimg.attached? %>
<div class="workflowimg-container" data-workflowimg-present="true">
<%= render partial: 'projects/show/workflow_img', locals: { experiment: experiment } %>

View file

@ -72,9 +72,9 @@
<i class="fas fa-sort-amount-up"></i>
</button>
<ul id="sortMenuDropdown" class="dropdown-menu sort-experiments-menu dropdown-menu-right" aria-labelledby="sortMenu">
<% %w(new old atoz ztoa archived_new archived_old).each_with_index do |sort, i| %>
<% %w(new old atoz ztoa id_asc id_desc archived_new archived_old).each_with_index do |sort, i| %>
<% if i.even? && i.positive? %>
<li class="divider" <%= i > 3 ? 'data-view-mode=archived' : '' %>></li>
<li class="divider" <%= i > 5 ? 'data-view-mode=archived' : '' %>></li>
<% end %>
<li <%= %w(archived_new archived_old).include?(sort) ? 'data-view-mode=archived' : '' %>>
<a class="<%= 'selected' if @current_sort == sort %>"

View file

@ -10,6 +10,7 @@
</div>
</th>
<th id="protocol-name"><%= t("protocols.index.thead_name") %></th>
<th id="protocol-code"><%= t("protocols.index.thead_code") %></th>
<th id="protocol-keywords"><%= t("protocols.index.thead_keywords") %></th>
<th id="protocol-nr-of-linked-children"><%= t("protocols.index.thead_nr_of_linked_children") %></th>
<% if @type == :public %>

View file

@ -10,7 +10,7 @@
<% end %>
</h4>
<div class="user-time">
<%= t('projects.reports.elements.module.user_time', timestamp: l(timestamp, format: :full)) %>
<%= t('projects.reports.elements.module.user_time', code: my_module.code, timestamp: l(timestamp, format: :full)) %>
</div>
<p class="module-start-date">
<% if my_module.started_on.present? %>

View file

@ -10,7 +10,7 @@
<% end %>
</div>
<div class="user-time">
<%= t('projects.reports.elements.module.protocol.user_time', timestamp: l(protocol.created_at, format: :full)) %>
<%= t('projects.reports.elements.module.protocol.user_time', code: protocol.code, timestamp: l(protocol.created_at, format: :full)) %>
</div>
<div class="row module-protocol-description">
<% if @settings.dig('task', 'protocol', 'description') && protocol.description.present? %>

View file

@ -8,7 +8,7 @@
<% end %>
</h2>
<div class="user-time">
<%= t('projects.reports.elements.project_header.user_time', timestamp: l(project.created_at, format: :full)) %>
<%= t('projects.reports.elements.project_header.user_time', code: project.code, timestamp: l(project.created_at, format: :full)) %>
</div>
</div>
<% if defined?(children) %>

View file

@ -27,6 +27,7 @@
</th>
<th id="project-name"><%= t('projects.reports.index.thead_project_name') %></th>
<th id="report-name"><%= t('projects.reports.index.thead_name') %></th>
<th id="report-id"><%= t('projects.reports.index.thead_id') %></th>
<th id="report-pdf"><%= t('projects.reports.index.pdf') %></th>
<th id="report-docx"><%= t('projects.reports.index.docx') %></th>
<th id="report-created-by"><%= t('projects.reports.index.thead_created_by') %></th>

View file

@ -117,6 +117,10 @@ en:
project: "Project"
my_module: "Task"
experiment: "Experiment"
repository: "Inventory"
repository_base: "Inventory"
protocol: "Protocol"
report: "Report"
errors:
models:
project:
@ -454,6 +458,7 @@ en:
more_comments: "More Comments"
card:
start_date: "Start date"
id: "ID"
visibility: "Visible to"
users: "Members"
name: "Project name"
@ -574,6 +579,7 @@ en:
thead_last_modified_by: "Last modified by"
thead_created_at: "Creation date"
thead_updated_at: "Last update date"
thead_id: "ID"
no_reports: "No reports!"
pdf: "PDF"
docx: "DOCX"
@ -734,10 +740,10 @@ en:
remove: "Remove report element from the report"
scinote_link: "SciNote link"
project_header:
user_time: "Project created on %{timestamp}."
user_time: "Project %{code} created on %{timestamp}."
title: "Report for project %{project}"
module:
user_time: "Task created on %{timestamp}."
user_time: "Task %{code} created on %{timestamp}."
started_on: "Start date: %{started_on}"
status: "Status:"
no_start_date: "No start date"
@ -749,7 +755,7 @@ en:
results: "Results"
protocol:
name: 'Protocol'
user_time: "Protocol created on %{timestamp}."
user_time: "Protocol %{code} created on %{timestamp}."
experiment:
user_time: "Experiment %{code} created on %{timestamp}."
no_description: "No description"
@ -971,6 +977,8 @@ en:
no_tags: "+ Add tags"
manage_tags: "Manage tags"
create_new_tag: "create new"
recent_protocols_from_repository: "Recent protocols from the Repository"
code: "ID: "
recent_protocols_from_repository: "Recent protocols from the Templates"
notes:
title: "Notes"
@ -1239,6 +1247,7 @@ en:
restore_button: "Restore"
card:
name: "Experiment"
id: "ID"
start_date: "Start date"
modified_date: "Modified date"
archived_date: "Archived date"
@ -1325,6 +1334,7 @@ en:
create: "Add"
create_new: "New"
edit:
id: "ID:"
new_module: "New task"
new_module_hover: "Drag me onto canvas"
save: "Save workflow"
@ -1332,6 +1342,7 @@ en:
cancel: "Cancel"
unsaved_work: "Are you sure you want to leave this page? All unsaved data will be lost."
drag_connections: "Drag connection/s from here"
no_module_id: "to be assigned after saving"
options_header: "Options"
edit_module: "Rename task"
task_access: "Task access"
@ -2573,6 +2584,7 @@ en:
publish: "Move to Team protocols"
archive_action: "Archive"
thead_name: "Name"
thead_code: "ID"
thead_keywords: "Keywords"
thead_nr_of_linked_children: "No. of linked tasks"
thead_published_by: "Published by"
@ -3163,12 +3175,14 @@ en:
comment_placeholder_new: "Add new comment…"
archived: "Archived"
sort:
new_html: "<i class=\"fas fa-sort-numeric-up\"></i>&nbsp;&nbsp;Started last"
new_html: "<i class=\"fas fa-sort-numeric-down-alt\"></i>&nbsp;&nbsp;Started last"
old_html: "<i class=\"fas fa-sort-numeric-down\"></i>&nbsp;&nbsp;Started first"
atoz_html: "<i class=\"fas fa-sort-alpha-down\"></i>&nbsp;&nbsp;Name A to Z"
ztoa_html: "<i class=\"fas fa-sort-alpha-up\"></i>&nbsp;&nbsp;Name Z to A"
ztoa_html: "<i class=\"fas fa-sort-alpha-down-alt\"></i>&nbsp;&nbsp;Name Z to A"
archived_new_html: "<span class=\"fa-stack\"><i class=\"fas fa-long-arrow-alt-up\"></i><i class=\"fas fa-archive\"></i></span>Archived last"
archived_old_html: "<span class=\"fa-stack\"><i class=\"fas fa-long-arrow-alt-down\"></i><i class=\"fas fa-archive\"></i></span>Archived first"
id_asc_html: "<i class=\"fas fa-sort-numeric-down\"></i>&nbsp;&nbsp;ID ascending"
id_desc_html: "<i class=\"fas fa-sort-numeric-down-alt\"></i>&nbsp;&nbsp;ID descending"
sort_new:
new: "Added last"
old: "Added first"

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
class AddCodeIndices < ActiveRecord::Migration[6.1]
def up
ActiveRecord::Base.connection.execute(
"CREATE INDEX index_projects_on_project_code ON "\
"projects using gin (('#{Project::ID_PREFIX}'::text || id) gin_trgm_ops);"
)
ActiveRecord::Base.connection.execute(
"CREATE INDEX index_my_modules_on_my_module_code ON "\
"my_modules using gin (('#{MyModule::ID_PREFIX}'::text || id) gin_trgm_ops);"
)
ActiveRecord::Base.connection.execute(
"CREATE INDEX index_protocols_on_protocol_code ON "\
"protocols using gin (('#{Protocol::ID_PREFIX}'::text || id) gin_trgm_ops);"
)
ActiveRecord::Base.connection.execute(
"CREATE INDEX index_reports_on_report_code ON "\
"reports using gin (('#{Report::ID_PREFIX}'::text || id) gin_trgm_ops);"
)
end
def down
remove_index :projects, name: 'index_projects_on_project_code'
remove_index :my_modules, name: 'index_my_modules_on_my_module_code'
remove_index :protocols, name: 'index_protocols_on_protocol_code'
remove_index :reports, name: 'index_reports_on_report_code'
end
end

View file

@ -50,8 +50,6 @@ CREATE FUNCTION public.trim_html_tags(input text, OUT output text) RETURNS text
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- Name: active_storage_attachments; Type: TABLE; Schema: public; Owner: -
--
@ -710,7 +708,6 @@ CREATE TABLE public.label_templates (
type character varying,
width_mm double precision,
height_mm double precision,
height_mm double precision,
unit integer DEFAULT 0,
density integer DEFAULT 12
);
@ -5330,6 +5327,13 @@ CREATE INDEX index_my_modules_on_experiment_id ON public.my_modules USING btree
CREATE INDEX index_my_modules_on_last_modified_by_id ON public.my_modules USING btree (last_modified_by_id);
--
-- Name: index_my_modules_on_my_module_code; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_my_modules_on_my_module_code ON public.my_modules USING gin ((('TA'::text || id)) public.gin_trgm_ops);
--
-- Name: index_my_modules_on_my_module_group_id; Type: INDEX; Schema: public; Owner: -
--
@ -5505,6 +5509,13 @@ CREATE INDEX index_projects_on_last_modified_by_id ON public.projects USING btre
CREATE INDEX index_projects_on_name ON public.projects USING gin (public.trim_html_tags((name)::text) public.gin_trgm_ops);
--
-- Name: index_projects_on_project_code; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_projects_on_project_code ON public.projects USING gin ((('PR'::text || id)) public.gin_trgm_ops);
--
-- Name: index_projects_on_project_folder_id; Type: INDEX; Schema: public; Owner: -
--
@ -5603,6 +5614,13 @@ CREATE INDEX index_protocols_on_name ON public.protocols USING gin (public.trim_
CREATE INDEX index_protocols_on_parent_id ON public.protocols USING btree (parent_id);
--
-- Name: index_protocols_on_protocol_code; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_protocols_on_protocol_code ON public.protocols USING gin ((('PT'::text || id)) public.gin_trgm_ops);
--
-- Name: index_protocols_on_protocol_type; Type: INDEX; Schema: public; Owner: -
--
@ -5743,6 +5761,13 @@ CREATE INDEX index_reports_on_name ON public.reports USING gin (public.trim_html
CREATE INDEX index_reports_on_project_id ON public.reports USING btree (project_id);
--
-- Name: index_reports_on_report_code; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_reports_on_report_code ON public.reports USING gin ((('RP'::text || id)) public.gin_trgm_ops);
--
-- Name: index_reports_on_team_id; Type: INDEX; Schema: public; Owner: -
--
@ -8568,6 +8593,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20220803122405'),
('20220818094636'),
('20220914124900'),
('20221007113010');
('20221007113010'),
('20221028085051');