mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-01-27 01:59:28 +08:00
Merge branch 'develop' into features/task-flows
This commit is contained in:
commit
5923a4c014
40 changed files with 255 additions and 135 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.19.4
|
||||
1.19.6
|
||||
|
|
|
@ -154,6 +154,7 @@ var MyModuleRepositories = (function() {
|
|||
pageLength: 25,
|
||||
sScrollX: '100%',
|
||||
sScrollXInner: '100%',
|
||||
stateDuration: 0,
|
||||
destroy: true,
|
||||
ajax: {
|
||||
url: $(tableContainer).data('source'),
|
||||
|
|
|
@ -405,7 +405,6 @@
|
|||
var $checkboxes = $(checkboxUl).find(".nested_fields");
|
||||
$checkboxes.each(function (itemPos) {
|
||||
var $this = $(this);
|
||||
|
||||
var $formGroup = $this.find(".form-group");
|
||||
var $label = $formGroup.find(".control-label");
|
||||
var $textInput = $formGroup.find(".checklist-item-text");
|
||||
|
@ -583,6 +582,11 @@
|
|||
}, 1000);
|
||||
|
||||
animateSpinner(null, true);
|
||||
|
||||
$(".nested_step_checklists ul").each(function () {
|
||||
reorderCheckboxData(this);
|
||||
});
|
||||
|
||||
DragNDropSteps.appendFilesToForm(ev).then(formData => {
|
||||
formData.append('step[description]', $tinyMCEInput);
|
||||
$.ajax({
|
||||
|
@ -591,11 +595,6 @@
|
|||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
beforeSend: function() {
|
||||
$(".nested_step_checklists ul").each(function () {
|
||||
reorderCheckboxData(this);
|
||||
});
|
||||
},
|
||||
success: function(data) {
|
||||
$($form.closest('.well')).after(data.html);
|
||||
var $new_step = $($form.closest('.well')).next();
|
||||
|
|
|
@ -398,6 +398,7 @@ var RepositoryDatatable = (function(global) {
|
|||
sScrollX: '100%',
|
||||
sScrollXInner: '100%',
|
||||
order: $(TABLE_ID).data('default-order'),
|
||||
stateDuration: 0,
|
||||
colReorder: {
|
||||
fixedColumnsLeft: 2,
|
||||
realtime: false
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
display: flex;
|
||||
|
||||
.add-result-dropdown {
|
||||
margin-right: auto;
|
||||
|
||||
li {
|
||||
cursor: pointer;
|
||||
padding: .5em 1em;
|
||||
|
@ -31,6 +29,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.collapse-expand-result {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.sort-result-dropdown {
|
||||
margin-left: .5em;
|
||||
|
||||
|
|
|
@ -3,23 +3,26 @@
|
|||
module Api
|
||||
module V1
|
||||
class ProtocolsController < BaseController
|
||||
before_action :load_team
|
||||
before_action :load_project
|
||||
before_action :load_experiment
|
||||
before_action :load_task
|
||||
include Api::V1::ExtraParams
|
||||
|
||||
before_action :load_team, :load_project, :load_experiment, :load_task
|
||||
before_action only: :show do
|
||||
load_protocol(:id)
|
||||
end
|
||||
|
||||
def index
|
||||
protocols = @task.protocols
|
||||
.page(params.dig(:page, :number))
|
||||
.per(params.dig(:page, :size))
|
||||
render jsonapi: protocols,
|
||||
each_serializer: ProtocolSerializer
|
||||
each_serializer: ProtocolSerializer, rte_rendering: render_rte?, team: @team
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_protocol
|
||||
@protocol = @task.protocols.find(params.require(:id))
|
||||
def show
|
||||
render jsonapi: @protocol, serializer: ProtocolSerializer,
|
||||
include: include_params,
|
||||
rte_rendering: render_rte?,
|
||||
team: @team
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,13 +16,15 @@ module Api
|
|||
|
||||
render jsonapi: steps, each_serializer: StepSerializer,
|
||||
include: include_params,
|
||||
rte_rendering: render_rte?
|
||||
rte_rendering: render_rte?,
|
||||
team: @team
|
||||
end
|
||||
|
||||
def show
|
||||
render jsonapi: @step, serializer: StepSerializer,
|
||||
include: include_params,
|
||||
rte_rendering: render_rte?
|
||||
rte_rendering: render_rte?,
|
||||
team: @team
|
||||
end
|
||||
|
||||
def create
|
||||
|
@ -59,7 +61,7 @@ module Api
|
|||
end
|
||||
|
||||
def permitted_includes
|
||||
%w(tables assets checklists checklists.checklist_items comments)
|
||||
%w(tables assets checklists checklists.checklist_items comments user)
|
||||
end
|
||||
|
||||
def load_step_for_managing
|
||||
|
|
|
@ -19,11 +19,11 @@ module Api
|
|||
.page(params.dig(:page, :number))
|
||||
.per(params.dig(:page, :size))
|
||||
|
||||
render jsonapi: tasks, each_serializer: TaskSerializer, rte_rendering: render_rte?
|
||||
render jsonapi: tasks, each_serializer: TaskSerializer, rte_rendering: render_rte?, team: @team
|
||||
end
|
||||
|
||||
def show
|
||||
render jsonapi: @task, serializer: TaskSerializer, rte_rendering: render_rte?
|
||||
render jsonapi: @task, serializer: TaskSerializer, rte_rendering: render_rte?, team: @team
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
|
@ -33,10 +33,7 @@ class CanvasController < ApplicationController
|
|||
to_archive = []
|
||||
if update_params[:remove].present?
|
||||
to_archive = update_params[:remove].split(',')
|
||||
if to_archive.all? do |id|
|
||||
is_int?(id) &&
|
||||
can_manage_module?(MyModule.find_by_id(id))
|
||||
end
|
||||
if to_archive.all? { |id| can_archive_module?(MyModule.find_by(id: id)) }
|
||||
to_archive.collect!(&:to_i)
|
||||
else
|
||||
return render_403
|
||||
|
@ -117,16 +114,14 @@ class CanvasController < ApplicationController
|
|||
# Okay, JSON parsed!
|
||||
unless to_move.is_a?(Hash) &&
|
||||
to_move.keys.all? do |id|
|
||||
id.is_a?(String) &&
|
||||
(!is_int?(id) || can_manage_module?(MyModule.find_by_id(id)))
|
||||
!is_int?(id) || can_move_module?(MyModule.find_by(id: id))
|
||||
end &&
|
||||
to_move.values.all? do |exp_id|
|
||||
exp_id.is_a?(String) &&
|
||||
can_manage_experiment?(Experiment.find_by_id(exp_id))
|
||||
can_manage_experiment?(Experiment.find_by(id: exp_id))
|
||||
end
|
||||
return render_403
|
||||
end
|
||||
rescue
|
||||
rescue StandardError
|
||||
return render_403
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,9 +6,9 @@ module Dashboard
|
|||
include MyModulesHelper
|
||||
|
||||
def show
|
||||
date = DateTime.parse(params[:date])
|
||||
start_date = date.at_beginning_of_month.utc - 7.days
|
||||
end_date = date.at_end_of_month.utc + 14.days
|
||||
date = params[:date].in_time_zone(current_user.time_zone)
|
||||
start_date = date.at_beginning_of_month.utc - 8.days
|
||||
end_date = date.at_end_of_month.utc + 15.days
|
||||
due_dates = current_user.my_modules.active.uncomplete
|
||||
.joins(experiment: :project)
|
||||
.where(experiments: { archived: false })
|
||||
|
@ -16,16 +16,18 @@ module Dashboard
|
|||
.where('my_modules.due_date > ? AND my_modules.due_date < ?', start_date, end_date)
|
||||
.joins(:protocols).where(protocols: { team_id: current_team.id })
|
||||
.pluck(:due_date)
|
||||
render json: { events: due_dates.map { |i| { date: i } } }
|
||||
render json: { events: due_dates.map { |i| { date: i.to_date } } }
|
||||
end
|
||||
|
||||
def day
|
||||
date = DateTime.parse(params[:date]).utc
|
||||
date = params[:date].in_time_zone(current_user.time_zone)
|
||||
start_date = date.utc
|
||||
end_date = date.end_of_day.utc
|
||||
my_modules = current_user.my_modules.active.uncomplete
|
||||
.joins(experiment: :project)
|
||||
.where(experiments: { archived: false })
|
||||
.where(projects: { archived: false })
|
||||
.where('DATE(my_modules.due_date) = DATE(?)', date)
|
||||
.where('my_modules.due_date > ? AND my_modules.due_date < ?', start_date, end_date)
|
||||
.where(projects: { team_id: current_team.id })
|
||||
render json: {
|
||||
html: render_to_string(partial: 'shared/my_modules_list_partial.html.erb', locals: {
|
||||
|
|
|
@ -4,8 +4,7 @@ class MyModuleRepositoriesController < ApplicationController
|
|||
include ApplicationHelper
|
||||
|
||||
before_action :load_my_module
|
||||
before_action :load_repository, except: %i(repositories_dropdown_list repositories_list_html export_repository)
|
||||
before_action :load_repository_or_snapshot, only: :export_repository
|
||||
before_action :load_repository, except: %i(repositories_dropdown_list repositories_list_html)
|
||||
before_action :check_my_module_view_permissions
|
||||
before_action :check_repository_view_permissions, except: %i(repositories_dropdown_list repositories_list_html)
|
||||
before_action :check_assign_repository_records_permissions, only: :update
|
||||
|
@ -120,6 +119,18 @@ class MyModuleRepositoriesController < ApplicationController
|
|||
def export_repository
|
||||
if params[:header_ids]
|
||||
RepositoryZipExport.generate_zip(params, @repository, current_user)
|
||||
|
||||
Activities::CreateActivityService.call(
|
||||
activity_type: :export_inventory_items_assigned_to_task,
|
||||
owner: current_user,
|
||||
subject: @repository,
|
||||
team: current_team,
|
||||
message_items: {
|
||||
my_module: @my_module.id,
|
||||
repository: @repository.id
|
||||
}
|
||||
)
|
||||
|
||||
render json: { message: t('zip_export.export_request_success') }, status: :ok
|
||||
else
|
||||
render json: { message: t('zip_export.export_error') }, status: :unprocessable_entity
|
||||
|
@ -138,12 +149,6 @@ class MyModuleRepositoriesController < ApplicationController
|
|||
render_404 unless @repository
|
||||
end
|
||||
|
||||
def load_repository_or_snapshot
|
||||
@repository = Repository.accessible_by_teams(current_team).find_by(id: params[:id])
|
||||
@repository ||= RepositorySnapshot.find_by(id: params[:id])
|
||||
render_404 unless @repository
|
||||
end
|
||||
|
||||
def check_my_module_view_permissions
|
||||
render_403 unless can_read_experiment?(@my_module.experiment)
|
||||
end
|
||||
|
|
|
@ -101,6 +101,28 @@ class MyModuleRepositorySnapshotsController < ApplicationController
|
|||
render json: {}
|
||||
end
|
||||
|
||||
def export_repository_snapshot
|
||||
if params[:header_ids]
|
||||
RepositoryZipExport.generate_zip(params, @repository_snapshot, current_user)
|
||||
|
||||
Activities::CreateActivityService.call(
|
||||
activity_type: :export_inventory_snapshot_items_assigned_to_task,
|
||||
owner: current_user,
|
||||
subject: @repository_snapshot,
|
||||
team: current_team,
|
||||
message_items: {
|
||||
my_module: @my_module.id,
|
||||
repository_snapshot: @repository_snapshot.id,
|
||||
created_at: @repository_snapshot.created_at
|
||||
}
|
||||
)
|
||||
|
||||
render json: { message: t('zip_export.export_request_success') }, status: :ok
|
||||
else
|
||||
render json: { message: t('zip_export.export_error') }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_my_module
|
||||
|
|
|
@ -9,7 +9,7 @@ class MyModulesController < ApplicationController
|
|||
|
||||
before_action :load_vars
|
||||
before_action :load_projects_tree, only: %i(protocols results activities archive)
|
||||
before_action :check_manage_permissions_archive, only: %i(update)
|
||||
before_action :check_archive_and_restore_permissions, only: %i(update)
|
||||
before_action :check_manage_permissions, only: %i(description due_date update_description update_protocol_description)
|
||||
before_action :check_view_permissions, except: %i(update update_description update_protocol_description
|
||||
toggle_task_state)
|
||||
|
@ -297,11 +297,11 @@ class MyModulesController < ApplicationController
|
|||
render_403 && return unless can_manage_module?(@my_module)
|
||||
end
|
||||
|
||||
def check_manage_permissions_archive
|
||||
def check_archive_and_restore_permissions
|
||||
render_403 && return unless if my_module_params[:archived] == 'false'
|
||||
can_restore_module?(@my_module)
|
||||
else
|
||||
can_manage_module?(@my_module)
|
||||
can_archive_module?(@my_module)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ class RepositoryRowsController < ApplicationController
|
|||
include ApplicationHelper
|
||||
include MyModulesHelper
|
||||
|
||||
before_action :load_repository
|
||||
before_action :load_repository_row, only: %i(update show assigned_task_list)
|
||||
before_action :check_read_permissions, except: %i(create update delete_records copy_records)
|
||||
before_action :load_repository, except: :show
|
||||
before_action :load_repository_row, only: %i(update assigned_task_list)
|
||||
before_action :check_read_permissions, except: %i(show create update delete_records copy_records)
|
||||
before_action :check_snapshotting_status, only: %i(create update delete_records copy_records)
|
||||
before_action :check_create_permissions, only: :create
|
||||
before_action :check_delete_permissions, only: %i(delete_records archive_records restore_records)
|
||||
|
@ -51,6 +51,11 @@ class RepositoryRowsController < ApplicationController
|
|||
end
|
||||
|
||||
def show
|
||||
@repository_row = RepositoryRow.find_by(id: params[:id])
|
||||
return render_404 unless @repository_row
|
||||
return render_404 unless @repository_row.repository_id == params[:repository_id].to_i
|
||||
return render_403 unless can_read_repository?(@repository_row.repository)
|
||||
|
||||
@assigned_modules = @repository_row.my_modules.joins(experiment: :project)
|
||||
@viewable_modules = @assigned_modules.viewable_by_user(current_user, current_user.teams)
|
||||
@private_modules = @assigned_modules - @viewable_modules
|
||||
|
|
|
@ -263,7 +263,9 @@ class SearchController < ApplicationController
|
|||
|
||||
def search_repository
|
||||
@repository = Repository.find_by_id(params[:repository])
|
||||
render_403 unless can_read_repository?(@repository)
|
||||
unless current_user.teams.include?(@repository.team) || @repository.private_shared_with?(current_user.teams)
|
||||
render_403
|
||||
end
|
||||
@repository_results = []
|
||||
if @repository_search_count_total > 0
|
||||
@repository_results =
|
||||
|
|
|
@ -13,8 +13,6 @@ class StepsController < ApplicationController
|
|||
before_action :check_manage_permissions, only: %i(new create edit update destroy move_up move_down)
|
||||
before_action :check_complete_and_checkbox_permissions, only: %i(toggle_step_state checklistitem_state)
|
||||
|
||||
before_action :update_checklist_item_positions, only: %i(create update)
|
||||
|
||||
def new
|
||||
@step = Step.new
|
||||
|
||||
|
@ -165,6 +163,9 @@ class StepsController < ApplicationController
|
|||
table.last_modified_by = current_user unless table.new_record?
|
||||
table.team = current_team
|
||||
end
|
||||
|
||||
update_checklist_items_without_callback(step_params_all)
|
||||
|
||||
if @step.save
|
||||
|
||||
TinyMceAsset.update_images(@step, params[:tiny_mce_images], current_user)
|
||||
|
@ -423,18 +424,6 @@ class StepsController < ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def update_checklist_item_positions
|
||||
if params["step"].present? && params["step"]["checklists_attributes"].present?
|
||||
params["step"]["checklists_attributes"].values.each do |cla|
|
||||
if cla["checklist_items_attributes"].present?
|
||||
cla["checklist_items_attributes"].each do |idx, item|
|
||||
item["position"] = idx
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This function is used for partial update of step references and
|
||||
# it's useful when you want to execute destroy action on attribute
|
||||
# collection separately from normal update action, for example if
|
||||
|
@ -534,6 +523,22 @@ class StepsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def update_checklist_items_without_callback(params)
|
||||
params.dig('checklists_attributes')&.values&.each do |cl|
|
||||
ck = @step.checklists.find_by(id: cl[:id])
|
||||
next if ck.nil? # ck is new checklist, skip update positions
|
||||
|
||||
cl['checklist_items_attributes']&.each do |item|
|
||||
# Here item is somehow array of index and parameters [0, paramteters<Object>], should be fixed on FE also
|
||||
item_record = ck.checklist_items.find_by(id: item[1][:id])
|
||||
|
||||
next unless item_record
|
||||
|
||||
item_record.update_attribute('position', item[1][:position])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_view_permissions
|
||||
render_403 unless can_read_protocol_in_module?(@protocol) || can_read_protocol_in_repository?(@protocol)
|
||||
end
|
||||
|
|
|
@ -15,15 +15,32 @@ class Users::PasswordsController < Devise::PasswordsController
|
|||
# end
|
||||
|
||||
# PUT /resource/password
|
||||
# def update
|
||||
# super
|
||||
# end
|
||||
def update
|
||||
self.resource = resource_class.reset_password_by_token(resource_params)
|
||||
yield resource if block_given?
|
||||
|
||||
# protected
|
||||
if resource.errors.empty?
|
||||
resource.unlock_access! if unlockable?(resource)
|
||||
if !resource.two_factor_auth_enabled?
|
||||
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
|
||||
set_flash_message!(:notice, flash_message)
|
||||
resource.after_database_authentication
|
||||
sign_in(resource_name, resource)
|
||||
else
|
||||
set_flash_message!(:notice, :updated_not_active)
|
||||
end
|
||||
respond_with resource, location: after_resetting_password_path_for(resource)
|
||||
else
|
||||
set_minimum_password_length
|
||||
respond_with resource
|
||||
end
|
||||
end
|
||||
|
||||
# def after_resetting_password_path_for(resource)
|
||||
# super(resource)
|
||||
# end
|
||||
protected
|
||||
|
||||
def after_resetting_password_path_for(resource)
|
||||
resource.two_factor_auth_enabled? ? new_session_path(resource_name) : after_sign_in_path_for(resource)
|
||||
end
|
||||
|
||||
# The path used after sending reset password instructions
|
||||
# def after_sending_reset_password_instructions_path_for(resource_name)
|
||||
|
|
|
@ -12,7 +12,7 @@ module GlobalActivitiesHelper
|
|||
if value.is_a? String
|
||||
value
|
||||
elsif value['type'] == 'Time' # use saved date for printing
|
||||
l(Time.at(value['value']), format: :full_date)
|
||||
l(Time.at(value['value']), format: :full)
|
||||
else
|
||||
no_links ? generate_name(value) : generate_link(value, activity)
|
||||
end
|
||||
|
|
|
@ -138,13 +138,11 @@ class Experiment < ApplicationRecord
|
|||
archive_modules(to_archive, current_user) if to_archive.any?
|
||||
|
||||
# Update only existing tasks positions to release positions for new tasks
|
||||
existing_positions = positions
|
||||
.slice(*positions.keys.map { |k| k unless k.to_s.start_with?('n') }.compact)
|
||||
existing_positions = positions.slice(*positions.keys.map { |k| k unless k.to_s.start_with?('n') }.compact)
|
||||
update_module_positions(existing_positions) if existing_positions.any?
|
||||
|
||||
# Move only existing tasks to release positions for new tasks
|
||||
existing_to_move = to_move
|
||||
.slice(*to_move.keys.map { |k| k unless k.to_s.start_with?('n') }.compact)
|
||||
existing_to_move = to_move.slice(*to_move.keys.map { |k| k unless k.to_s.start_with?('n') }.compact)
|
||||
move_modules(existing_to_move, current_user) if existing_to_move.any?
|
||||
|
||||
# add new modules
|
||||
|
|
|
@ -5,7 +5,6 @@ Canaid::Permissions.register_for(MyModule) do
|
|||
manage_users_in_module
|
||||
assign_repository_rows_to_module
|
||||
assign_sample_to_module
|
||||
change_my_module_flow_status
|
||||
create_comments_in_module
|
||||
create_my_module_repository_snapshot
|
||||
manage_my_module_repository_snapshots)
|
||||
|
@ -17,12 +16,17 @@ Canaid::Permissions.register_for(MyModule) do
|
|||
end
|
||||
end
|
||||
|
||||
# module: update, archive, move
|
||||
# module: update
|
||||
# result: create, update
|
||||
can :manage_module do |user, my_module|
|
||||
can_manage_experiment?(user, my_module.experiment)
|
||||
end
|
||||
|
||||
# module: archive
|
||||
can :archive_module do |user, my_module|
|
||||
can_manage_experiment?(user, my_module.experiment)
|
||||
end
|
||||
|
||||
# NOTE: Must not be dependent on canaid parmision for which we check if it's
|
||||
# active
|
||||
# module: restore
|
||||
|
@ -31,6 +35,11 @@ Canaid::Permissions.register_for(MyModule) do
|
|||
my_module.archived?
|
||||
end
|
||||
|
||||
# module: move
|
||||
can :move_module do |user, my_module|
|
||||
can_manage_experiment?(user, my_module.experiment)
|
||||
end
|
||||
|
||||
# module: assign/reassign/unassign users
|
||||
can :manage_users_in_module do |user, my_module|
|
||||
user.is_owner_of_project?(my_module.experiment.project)
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
module Api
|
||||
module V1
|
||||
class ProtocolSerializer < ActiveModel::Serializer
|
||||
include ApplicationHelper
|
||||
include ActionView::Helpers::TextHelper
|
||||
include InputSanitizeHelper
|
||||
|
||||
type :protocols
|
||||
attributes :id, :name, :authors, :description, :protocol_type
|
||||
has_many :protocol_keywords,
|
||||
|
@ -12,6 +16,17 @@ module Api
|
|||
unless: -> { object.protocol_keywords.empty? }
|
||||
has_many :steps, serializer: StepSerializer, if: -> { object.steps.any? }
|
||||
belongs_to :parent, serializer: ProtocolSerializer, if: -> { object.parent.present? }
|
||||
|
||||
def description
|
||||
if instance_options[:rte_rendering]
|
||||
custom_auto_link(object.tinymce_render(:description),
|
||||
simple_format: false,
|
||||
tags: %w(img),
|
||||
team: instance_options[:team])
|
||||
else
|
||||
object.description
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,8 +8,9 @@ module Api
|
|||
include InputSanitizeHelper
|
||||
|
||||
type :steps
|
||||
attributes :id, :name, :description, :position, :completed
|
||||
attributes :id, :name, :description, :created_at, :position, :completed
|
||||
attribute :completed_on, if: -> { object.completed? }
|
||||
belongs_to :user, serializer: UserSerializer
|
||||
belongs_to :protocol, serializer: ProtocolSerializer
|
||||
has_many :assets, serializer: AssetSerializer
|
||||
has_many :checklists, serializer: ChecklistSerializer
|
||||
|
@ -18,7 +19,10 @@ module Api
|
|||
|
||||
def description
|
||||
if instance_options[:rte_rendering]
|
||||
custom_auto_link(object.tinymce_render(:description), simple_format: false, tags: %w(img))
|
||||
custom_auto_link(object.tinymce_render(:description),
|
||||
simple_format: false,
|
||||
tags: %w(img),
|
||||
team: instance_options[:team])
|
||||
else
|
||||
object.description
|
||||
end
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
module Api
|
||||
module V1
|
||||
class TaskSerializer < ActiveModel::Serializer
|
||||
include ApplicationHelper
|
||||
include ActionView::Helpers::TextHelper
|
||||
include InputSanitizeHelper
|
||||
|
||||
type :tasks
|
||||
attributes :id, :name, :started_on, :due_date, :description, :state, :archived
|
||||
has_many :output_tasks, key: :outputs,
|
||||
|
@ -22,7 +26,10 @@ module Api
|
|||
|
||||
def description
|
||||
if instance_options[:rte_rendering]
|
||||
custom_auto_link(object.tinymce_render(:description), simple_format: false, tags: %w(img))
|
||||
custom_auto_link(object.tinymce_render(:description),
|
||||
simple_format: false,
|
||||
tags: %w(img),
|
||||
team: instance_options[:team])
|
||||
else
|
||||
object.description
|
||||
end
|
||||
|
|
|
@ -68,7 +68,7 @@ class ActivitiesService
|
|||
end
|
||||
|
||||
def self.my_module_activities(my_module)
|
||||
subjects_with_children = load_subjects_children(my_module: [my_module.id])
|
||||
subjects_with_children = load_subjects_children('MyModule': [my_module.id])
|
||||
query = Activity.where(project: my_module.experiment.project)
|
||||
query.where(
|
||||
subjects_with_children.map { '(subject_type = ? AND subject_id IN(?))' }.join(' OR '),
|
||||
|
|
|
@ -19,12 +19,17 @@ module Reports::Docx::PrivateMethods
|
|||
tiny_mce_table(elem[:data])
|
||||
elsif elem[:type] == 'newline'
|
||||
style = elem[:style] || {}
|
||||
@docx.p elem[:value] do
|
||||
align style[:align]
|
||||
color style[:color]
|
||||
bold style[:bold]
|
||||
italic style[:italic]
|
||||
style style[:style] if style[:style]
|
||||
# print heading if its heading
|
||||
# Mixing heading with other style setting causes problems for Word
|
||||
if %w(h1 h2 h3 h4 h5).include?(style[:style])
|
||||
@docx.public_send(style[:style], elem[:value])
|
||||
else
|
||||
@docx.p elem[:value] do
|
||||
align style[:align]
|
||||
color style[:color]
|
||||
bold style[:bold]
|
||||
italic style[:italic]
|
||||
end
|
||||
end
|
||||
elsif elem[:type] == 'image'
|
||||
Reports::Docx.render_img_element(@docx, elem)
|
||||
|
@ -287,7 +292,7 @@ module Reports::Docx::PrivateMethods
|
|||
Reports::Docx.render_p_element(c, cell_content,
|
||||
scinote_url: scinote_url, link_style: link_style, skip_br: true)
|
||||
elsif cell_content[:type] == 'table'
|
||||
c.table formated_cell_content[:data]
|
||||
c.table formated_cell_content[:data], border_size: Constants::REPORT_DOCX_TABLE_BORDER_SIZE
|
||||
elsif cell_content[:type] == 'image'
|
||||
Reports::Docx.render_img_element(c, cell_content, table: { columns: row.children.length / 3 })
|
||||
end
|
||||
|
@ -301,7 +306,7 @@ module Reports::Docx::PrivateMethods
|
|||
if options[:nested_table]
|
||||
docx_table
|
||||
else
|
||||
@docx.table docx_table
|
||||
@docx.table docx_table, border_size: Constants::REPORT_DOCX_TABLE_BORDER_SIZE
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -44,18 +44,18 @@ class RepositoryTableStateColumnUpdateService
|
|||
end
|
||||
end
|
||||
|
||||
if state.dig('order', 0, 0) == old_column_index
|
||||
if state.dig('order', 0, 0).to_i == old_column_index
|
||||
# Fallback to default order if user had table ordered by
|
||||
# the deleted column
|
||||
state['order'] = Constants::REPOSITORY_TABLE_DEFAULT_STATE['order']
|
||||
elsif state.dig('order', 0, 0) > old_column_index
|
||||
elsif state.dig('order', 0, 0).to_i > old_column_index
|
||||
state['order'][0][0] -= 1
|
||||
end
|
||||
|
||||
state['length'] = (state['length'] - 1)
|
||||
state['time'] = (Time.now.to_f * 1_000).to_i
|
||||
table_state.save
|
||||
rescue NoMethodError => e
|
||||
rescue StandardError => e
|
||||
Rails.logger.error e.message
|
||||
RepositoryTableStateService.new(user, repository).create_default_state
|
||||
end
|
||||
|
|
|
@ -7,11 +7,12 @@ module RepositoryZipExport
|
|||
# Fetch rows in the same order as in the currently viewed datatable
|
||||
if params[:my_module_id]
|
||||
rows = if repository.is_a?(RepositorySnapshot)
|
||||
repository.repository_rows
|
||||
else
|
||||
repository.repository_rows.joins(:my_module_repository_rows)
|
||||
.where(my_module_repository_rows: { my_module_id: params[:my_module_id] })
|
||||
end
|
||||
repository.repository_rows
|
||||
else
|
||||
repository.repository_rows
|
||||
.joins(:my_module_repository_rows)
|
||||
.where(my_module_repository_rows: { my_module_id: params[:my_module_id] })
|
||||
end
|
||||
else
|
||||
ordered_row_ids = params[:row_ids]
|
||||
id_row_map = RepositoryRow.where(id: ordered_row_ids,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
data-module-conns="<%= construct_module_connections(my_module) %>">
|
||||
|
||||
<% module_group = my_module.my_module_group %>
|
||||
<% can_manage_module_group = module_group && (module_group.new_record? || module_group.my_modules.all? { |my_module| can_manage_module?(my_module) }) %>
|
||||
|
||||
<div class="panel-heading">
|
||||
|
||||
|
@ -21,35 +20,35 @@
|
|||
<li class="dropdown-header"><%= t('projects.index.options_header') %></li>
|
||||
<% if can_manage_module?(my_module) %>
|
||||
<li>
|
||||
<a class="edit-module" href="" data-module-id="<%= my_module.id %>"><%=t "experiments.canvas.edit.edit_module" %></a>
|
||||
<a class="edit-module" href="" data-module-id="<%= my_module.id %>"><%= t('experiments.canvas.edit.edit_module') %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if can_manage_experiment?(my_module.experiment) %>
|
||||
<li>
|
||||
<a class ="clone-module" href="" data-module-id="<%= my_module.id %>"><%=t "experiments.canvas.edit.clone_module" %></a>
|
||||
<a class ="clone-module" href="" data-module-id="<%= my_module.id %>"><%= t('experiments.canvas.edit.clone_module') %></a>
|
||||
</li>
|
||||
<li <%= 'style=display:none;' if my_module.my_module_group.blank? %>>
|
||||
<a class ="clone-module-group" href="" data-module-id="<%= my_module.id %>"><%=t "experiments.canvas.edit.clone_module_group" %></a>
|
||||
<a class ="clone-module-group" href="" data-module-id="<%= my_module.id %>"><%= t('experiments.canvas.edit.clone_module_group') %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if can_manage_module?(my_module) %>
|
||||
<% if can_move_module?(my_module) %>
|
||||
<li>
|
||||
<a class="move-module" href="" data-module-id="<%= my_module.id %>"><%=t "experiments.canvas.edit.move_module" %></a>
|
||||
<a class="move-module" href="" data-module-id="<%= my_module.id %>"><%= t('experiments.canvas.edit.move_module') %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if can_manage_module_group %>
|
||||
<% if module_group.my_modules.all? { |my_module| can_move_module?(my_module) } %>
|
||||
<li>
|
||||
<a class="move-module-group" href="" data-module-id="<%= my_module.id %>"><%=t "experiments.canvas.edit.move_module_group" %></a>
|
||||
<a class="move-module-group" href="" data-module-id="<%= my_module.id %>"><%= t('experiments.canvas.edit.move_module_group') %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if can_manage_module?(my_module) %>
|
||||
<% if can_archive_module?(my_module) %>
|
||||
<li>
|
||||
<a class="delete-module" href="" data-module-id="<%= my_module.id %>"><%=t "experiments.canvas.edit.delete_module" %></a>
|
||||
<a class="delete-module" href="" data-module-id="<%= my_module.id %>"><%= t('experiments.canvas.edit.delete_module') %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if can_manage_module_group %>
|
||||
<% if module_group.my_modules.all? { |my_module| can_archive_module?(my_module) } %>
|
||||
<li data-hook="archive-module-group">
|
||||
<a class ="delete-module-group" href="" data-module-id="<%= my_module.id %>"><%=t "experiments.canvas.edit.delete_module_group" %></a>
|
||||
<a class ="delete-module-group" href="" data-module-id="<%= my_module.id %>"><%= t('experiments.canvas.edit.delete_module_group') %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
@ -59,7 +58,7 @@
|
|||
|
||||
<% if can_manage_experiment?(my_module.experiment) %>
|
||||
<div class="panel-body ep">
|
||||
<%=t "experiments.canvas.edit.drag_connections" %>
|
||||
<%= t('experiments.canvas.edit.drag_connections') %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<%= t('my_modules.repository.snapshots.full_view.versions_sidebar_button') %>
|
||||
</button>
|
||||
<button id="exportAssignedItems" type="button" class="btn btn-secondary">
|
||||
<span class="fas fa-download"></span>
|
||||
<span class="fas fa-upload"></span>
|
||||
<%= t('my_modules.repository.snapshots.full_view.export_button') %>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
data-default-order="<%= default_snapshot_table_order_as_js_array %>"
|
||||
data-default-table-columns="<%= default_snapshot_table_columns %>"
|
||||
data-load-state-url="<%= repository_load_table_state_path(@repository_snapshot) %>"
|
||||
data-export-url="<%= export_repository_my_module_repository_path(@my_module ,@repository_snapshot) %>"
|
||||
data-export-url="<%= export_repository_snapshot_my_module_repository_snapshot_path(@my_module, @repository_snapshot) %>"
|
||||
data-versions-sidebar-url="<%= full_view_sidebar_my_module_repository_snapshots_path(@my_module, @repository_snapshot.parent_id) %>"
|
||||
>
|
||||
<thead>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="sci-btn-group">
|
||||
<div class="sci-btn-group collapse-expand-result">
|
||||
<button class="btn btn-light" id="results-collapse-btn">
|
||||
<span class="fas fa-caret-up"></span>
|
||||
<span class="hidden-xs-custom"><%= t'my_modules.results.collapse_label' %></span>
|
||||
|
|
|
@ -57,8 +57,11 @@
|
|||
(function () {
|
||||
var formErrors = {};
|
||||
|
||||
<% resource.errors.each do |err, m| %>
|
||||
formErrors["<%= err %>"] =["<%= m %>"];
|
||||
<% resource.errors.as_json.each do |err, messages| %>
|
||||
formErrors["<%= err %>"]=[]
|
||||
<% messages.each do |message| %>
|
||||
formErrors["<%= err %>"].push('<%= message %>');
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
$("form").renderFormErrors("user", formErrors, false);
|
||||
|
@ -71,8 +74,11 @@
|
|||
(function () {
|
||||
var formErrors = {};
|
||||
|
||||
<% @team.errors.each do |err, m| %>
|
||||
formErrors["<%= err %>"] =["<%= m %>"];
|
||||
<% @team.errors.as_json.each do |err, messages| %>
|
||||
formErrors["<%= err %>"]=[]
|
||||
<% messages.each do |message| %>
|
||||
formErrors["<%= err %>"].push('<%= message %>');
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
$("form").renderFormErrors("team", formErrors, false);
|
||||
|
|
|
@ -65,9 +65,11 @@
|
|||
<script>
|
||||
(function () {
|
||||
var formErrors = {};
|
||||
|
||||
<% resource.errors.each do |err, m| %>
|
||||
formErrors["<%= err %>"] =["<%= m %>"];
|
||||
<% resource.errors.as_json.each do |err, messages| %>
|
||||
formErrors["<%= err %>"]=[]
|
||||
<% messages.each do |message| %>
|
||||
formErrors["<%= err %>"].push('<%= message %>');
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
$("form").renderFormErrors("user", formErrors, false);
|
||||
|
@ -80,8 +82,11 @@
|
|||
(function () {
|
||||
var formErrors = {};
|
||||
|
||||
<% @team.errors.each do |err, m| %>
|
||||
formErrors["<%= err %>"] =["<%= m %>"];
|
||||
<% @team.errors.as_json.each do |err, messages| %>
|
||||
formErrors["<%= err %>"]=[]
|
||||
<% messages.each do |message| %>
|
||||
formErrors["<%= err %>"].push('<%= message %>');
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
$("form").renderFormErrors('team', formErrors, false);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<%= link_to t("devise.links.not_receive_confirmation"), new_confirmation_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' && flash[:alert] == t('devise.failure.locked') %>
|
||||
<%= link_to t("devise.links.not_receive_unlock"), new_unlock_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
|
|
|
@ -243,7 +243,9 @@ Devise.setup do |config|
|
|||
|
||||
# When set to false, does not sign a user in automatically after their password is
|
||||
# reset. Defaults to true, so a user is signed in automatically after a reset.
|
||||
config.sign_in_after_reset_password = false
|
||||
#
|
||||
# This setting has no effect, controller has been overriden at controllers/users/passwords_controller.rb
|
||||
# config.sign_in_after_reset_password = false
|
||||
|
||||
# ==> Configuration for :encryptable
|
||||
# Allow you to use another encryption algorithm besides bcrypt (default). You can use
|
||||
|
|
|
@ -143,9 +143,8 @@ class Extends
|
|||
step: nil
|
||||
}
|
||||
|
||||
ACTIVITY_MESSAGE_ITEMS_TYPES =
|
||||
ACTIVITY_SUBJECT_TYPES + %w(User Tag RepositoryColumn RepositoryRow Step Asset TinyMceAsset Repository)
|
||||
.freeze
|
||||
ACTIVITY_MESSAGE_ITEMS_TYPES = ACTIVITY_SUBJECT_TYPES + %w(User Tag RepositoryColumn RepositoryRow Step
|
||||
Asset TinyMceAsset Repository RepositorySnapshot).freeze
|
||||
|
||||
ACTIVITY_TYPES = {
|
||||
create_project: 0,
|
||||
|
@ -287,7 +286,9 @@ class Extends
|
|||
archive_inventory_item: 142,
|
||||
restore_inventory_item: 143,
|
||||
archive_inventory: 144,
|
||||
restore_inventory: 145
|
||||
restore_inventory: 145,
|
||||
export_inventory_items_assigned_to_task: 146,
|
||||
export_inventory_snapshot_items_assigned_to_task: 147
|
||||
}
|
||||
|
||||
ACTIVITY_GROUPS = {
|
||||
|
|
|
@ -825,7 +825,7 @@ en:
|
|||
no_assigned_items: 'No items assigned'
|
||||
no_snapshots_label: 'You have not created any snapshots yet. To do so click the button bellow.'
|
||||
versions_sidebar_button: 'View versions'
|
||||
export_button: "Export .csv"
|
||||
export_button: "Export items"
|
||||
create_button: 'Create snapshot'
|
||||
set_default_button: 'Set as default view'
|
||||
created_by: 'by %{full_name}'
|
||||
|
|
|
@ -173,6 +173,8 @@ en:
|
|||
delete_chemical_structure_on_protocol_html: "%{user} deleted chemical structure %{asset_name} on protocol %{protocol}."
|
||||
delete_chemical_structure_on_task_html: "%{user} deleted chemical structure %{asset_name} on task %{my_module}."
|
||||
protocol_description_in_task_edited_html: "%{user} edited protocol description on task %{my_module}."
|
||||
export_inventory_items_assigned_to_task_html: "%{user} exported inventory item(s) assigned to task %{my_module} from inventory %{repository}: Live version."
|
||||
export_inventory_snapshot_items_assigned_to_task_html: "%{user} exported inventory item(s) assigned to task %{my_module} from inventory %{repository_snapshot}: Snapshot of %{created_at}."
|
||||
|
||||
activity_name:
|
||||
create_project: "Project created"
|
||||
|
@ -311,6 +313,8 @@ en:
|
|||
delete_chemical_structure_on_protocol: "Chemical structure on protocol deleted"
|
||||
delete_chemical_structure_on_task: "Chemical structure on task deleted"
|
||||
protocol_description_in_task_edited: "Protocol description in task edited"
|
||||
export_inventory_items_assigned_to_task: "Task-assigned inventory items exported (live version)"
|
||||
export_inventory_snapshot_items_assigned_to_task: "Task-assigned inventory items exported (snapshot)"
|
||||
|
||||
activity_group:
|
||||
projects: "Projects"
|
||||
|
|
|
@ -14,7 +14,8 @@ Rails.application.routes.draw do
|
|||
sessions: 'users/sessions',
|
||||
invitations: 'users/invitations',
|
||||
confirmations: 'users/confirmations',
|
||||
omniauth_callbacks: 'users/omniauth_callbacks' }
|
||||
omniauth_callbacks: 'users/omniauth_callbacks',
|
||||
passwords: 'users/passwords' }
|
||||
|
||||
root 'dashboards#show'
|
||||
|
||||
|
@ -365,6 +366,7 @@ Rails.application.routes.draw do
|
|||
member do
|
||||
get :full_view_table
|
||||
post :index_dt
|
||||
post :export_repository_snapshot
|
||||
get :status
|
||||
end
|
||||
|
||||
|
@ -684,7 +686,7 @@ Rails.application.routes.draw do
|
|||
resources :task_tags, only: %i(index show),
|
||||
path: 'tags',
|
||||
as: :tags
|
||||
resources :protocols, only: %i(index) do
|
||||
resources :protocols, only: %i(index show) do
|
||||
resources :steps do
|
||||
resources :assets, only: %i(index show create), path: 'attachments'
|
||||
resources :checklists, path: 'checklists' do
|
||||
|
|
|
@ -20,6 +20,7 @@ Scenario: Unsuccessful add Text result
|
|||
Given I am on Task results page
|
||||
And I click "Add new result" button
|
||||
And I click on "Text" within dropdown menu
|
||||
And WAIT
|
||||
And I click "Add" button
|
||||
Then I should see "can't be blank"
|
||||
And I click "Cancel" button
|
||||
|
|
Loading…
Reference in a new issue