diff --git a/app/assets/javascripts/my_modules/protocols.js b/app/assets/javascripts/my_modules/protocols.js index c96749baa..183dc905c 100644 --- a/app/assets/javascripts/my_modules/protocols.js +++ b/app/assets/javascripts/my_modules/protocols.js @@ -18,7 +18,8 @@ function initEditMyModuleDescription() { { onSaveCallback: () => { Prism.highlightAllUnder(viewObject.get(0)); - } + }, + assignableMyModuleId: $('#my_module_description_textarea').data('object-id') } ); }).on('click', 'a', function(e) { diff --git a/app/assets/javascripts/my_modules/repositories.js b/app/assets/javascripts/my_modules/repositories.js index 6f0701c28..480865a6c 100644 --- a/app/assets/javascripts/my_modules/repositories.js +++ b/app/assets/javascripts/my_modules/repositories.js @@ -841,6 +841,9 @@ var MyModuleRepositories = (function() { reloadFullViewTable: () => { if (!FULL_VIEW_TABLE) return; FULL_VIEW_TABLE.ajax.reload(null, false); + }, + reloadRepositoriesList: (repositoryId, expand = false) => { + reloadRepositoriesList(repositoryId, expand); } }; }()); diff --git a/app/assets/javascripts/my_modules/stock.js b/app/assets/javascripts/my_modules/stock.js index 688b60bbd..fd40c5408 100644 --- a/app/assets/javascripts/my_modules/stock.js +++ b/app/assets/javascripts/my_modules/stock.js @@ -25,7 +25,7 @@ var MyModuleStockConsumption = (function() { $manageModal.find('.modal-content').html(result.html); $manageModal.modal('show'); focusStockConsumption(); - SmartAnnotation.init($(CONSUMPTION_MODAL + ' #comment')[0]); + SmartAnnotation.init($(CONSUMPTION_MODAL + ' #comment')[0], false); $('#stock_consumption').on('input', function() { let initialValue = new Decimal($(this).data('initial-value') || 0); diff --git a/app/assets/javascripts/repositories/renderers/new_renderers.js b/app/assets/javascripts/repositories/renderers/new_renderers.js index c626f98d0..7310690dd 100644 --- a/app/assets/javascripts/repositories/renderers/new_renderers.js +++ b/app/assets/javascripts/repositories/renderers/new_renderers.js @@ -33,7 +33,7 @@ $.fn.dataTable.render.newRepositoryTextValue = function(formId, columnId, $cell) data-type="RepositoryTextValue"> `); - SmartAnnotation.init($cell.find('input')); + SmartAnnotation.init($cell.find('input'), false); }; $.fn.dataTable.render.newRepositoryListValue = function(formId, columnId, $cell) { diff --git a/app/assets/javascripts/repositories/repository_datatable.js b/app/assets/javascripts/repositories/repository_datatable.js index a9f4befd8..d391882cf 100644 --- a/app/assets/javascripts/repositories/repository_datatable.js +++ b/app/assets/javascripts/repositories/repository_datatable.js @@ -266,6 +266,10 @@ var RepositoryDatatable = (function(global) { }); } + function updateSelectedRowsForAssignments() { + window.AssignItemsToTaskModalComponent.setShowCallback(() => rowsSelected); + } + function checkAvailableColumns() { $.ajax({ url: $(TABLE_ID).data('available-columns'), @@ -730,6 +734,7 @@ var RepositoryDatatable = (function(global) { }) initRowSelection(); + updateSelectedRowsForAssignments(); // $(window).resize(() => { // setTimeout(() => { // adjustTableHeader(); diff --git a/app/assets/javascripts/repositories/stock.js b/app/assets/javascripts/repositories/stock.js index 306543708..82a43a644 100644 --- a/app/assets/javascripts/repositories/stock.js +++ b/app/assets/javascripts/repositories/stock.js @@ -120,7 +120,7 @@ var RepositoryStockValues = (function() { this.value = formatDecimalValue(this.value, decimals); }); - SmartAnnotation.init($('#repository-stock-value-comment')[0]); + SmartAnnotation.init($('#repository-stock-value-comment')[0], false); $('#repository-stock-value-comment').on('input', function() { $(this).closest('.sci-input-container').toggleClass( diff --git a/app/assets/javascripts/results/result_texts.js b/app/assets/javascripts/results/result_texts.js index 814d48b41..38ac50000 100644 --- a/app/assets/javascripts/results/result_texts.js +++ b/app/assets/javascripts/results/result_texts.js @@ -27,7 +27,9 @@ formAjaxResultText($form); Results.initCancelFormButton($form, initNewReslutText); Results.toggleResultEditButtons(false); - TinyMCE.init('#result_text_attributes_textarea'); + TinyMCE.init('#result_text_attributes_textarea', { + assignableMyModuleId: $('#result_text_attributes_textarea').data('my-module-id') + }); $('#result_name').focus(); }, error: function() { @@ -58,7 +60,9 @@ Results.toggleResultEditButtons(true); }); Results.toggleResultEditButtons(false); - TinyMCE.init('#result_text_attributes_textarea'); + TinyMCE.init('#result_text_attributes_textarea', { + assignableMyModuleId: $('#result_text_attributes_textarea').data('my-module-id') + }); $('#result_name').focus(); }); } diff --git a/app/assets/javascripts/shared/inline_editing.js b/app/assets/javascripts/shared/inline_editing.js index b6f568059..e9950ece1 100644 --- a/app/assets/javascripts/shared/inline_editing.js +++ b/app/assets/javascripts/shared/inline_editing.js @@ -22,7 +22,7 @@ var inlineEditing = (function() { function initSmartAnnotation(container) { if (container.data('smart-annotation')) { - SmartAnnotation.init(inputField(container)); + SmartAnnotation.init(inputField(container), false); } } diff --git a/app/assets/javascripts/sitewide/atwho_res.js b/app/assets/javascripts/sitewide/atwho_res.js index 8f9b81cf3..9e68c28df 100644 --- a/app/assets/javascripts/sitewide/atwho_res.js +++ b/app/assets/javascripts/sitewide/atwho_res.js @@ -1,4 +1,4 @@ -/* global _ */ +/* global PerfectScrollbar MyModuleRepositories HelperModule _ */ var SmartAnnotation = (function() { 'use strict'; @@ -11,7 +11,7 @@ var SmartAnnotation = (function() { }); } - function SetAtWho(field, deferred) { + function SetAtWho(field, deferred, assignableMyModuleId) { var FilterTypeEnum = Object.freeze({ USER: { tag: 'users', dataUrl: $(document.body).attr('data-atwho-users-url') }, TASK: { tag: 'sa-tasks', dataUrl: $(document.body).attr('data-atwho-task-url') }, @@ -67,6 +67,7 @@ var SmartAnnotation = (function() { let activeRepository = repositoryTab.find('.btn-primary'); if (activeRepository.length) { params.repository_id = activeRepository.data('object-id'); + params.assignable_my_module_id = assignableMyModuleId; } } $.getJSON(filterType.dataUrl, params, function(data) { @@ -81,6 +82,10 @@ var SmartAnnotation = (function() { $currentAtWho.find(`.repository-object[data-object-id="${data.repository}"]`) .addClass('btn-primary').removeClass('btn-light'); } + if ($('.atwho-scroll-container')[0]) { + // eslint-disable-next-line no-new + new PerfectScrollbar($('.atwho-scroll-container')[0]); + } }); return true; }, @@ -141,6 +146,24 @@ var SmartAnnotation = (function() { $(this).addClass('btn-primary').removeClass('btn-light'); $(field).click().focus(); }); + $currentAtWho.on('click', '.atwho-assign-button', function() { + let el = $(this); + $.ajax({ + method: 'POST', + url: el.data('assign-url'), + data: { repository_row_id: el.data('repository-row-id') }, + dataType: 'json', + success: function(data) { + if (typeof MyModuleRepositories !== 'undefined') { + MyModuleRepositories.reloadRepositoriesList(el.data('repository-id')); + } + HelperModule.flashAlertMsg(data.flash, 'success'); + }, + error: function(response) { + HelperModule.flashAlertMsg(response.responseJSON.flash, 'danger'); + } + }); + }); if ($currentAtWho.find('.tab-pane.active').length === 0) { let filterType = DEFAULT_SEARCH_FILTER.tag; @@ -223,8 +246,8 @@ var SmartAnnotation = (function() { $('.atwho-header-res').find('.fa-times').click(); } - function initialize(field, deferred) { - var atWho = new SetAtWho(field, deferred); + function initialize(field, deferred, assignableMyModuleId) { + var atWho = new SetAtWho(field, deferred, assignableMyModuleId); atWho.init(); } @@ -240,7 +263,7 @@ var SmartAnnotation = (function() { (function() { $(document).on('focus', '[data-atwho-edit]', function() { if (_.isUndefined($(this).data('atwho'))) { - SmartAnnotation.init(this); + SmartAnnotation.init(this, false); } }); diff --git a/app/assets/javascripts/sitewide/comments_sidebar.js b/app/assets/javascripts/sitewide/comments_sidebar.js index f59f5075f..d6a35193a 100644 --- a/app/assets/javascripts/sitewide/comments_sidebar.js +++ b/app/assets/javascripts/sitewide/comments_sidebar.js @@ -147,7 +147,7 @@ var CommentsSidebar = (function() { function initInputField() { if ($(SIDEBAR).find('.comment-input-field').length) { - SmartAnnotation.init($(SIDEBAR).find('.comment-input-field')); + SmartAnnotation.init($(SIDEBAR).find('.comment-input-field'), false); } } diff --git a/app/assets/javascripts/sitewide/repository_row_info_modal.js b/app/assets/javascripts/sitewide/repository_row_info_modal.js index 4d01b7e20..130f9a7b9 100644 --- a/app/assets/javascripts/sitewide/repository_row_info_modal.js +++ b/app/assets/javascripts/sitewide/repository_row_info_modal.js @@ -1,13 +1,18 @@ -/* global bwipjs PrintModalComponent RepositoryDatatable */ +/* global bwipjs PrintModalComponent RepositoryDatatable HelperModule MyModuleRepositories */ (function() { 'use strict'; $(document).on('click', '.record-info-link', function(e) { var that = $(this); + let params = {}; + if ($('.my-modules-protocols-index').length) { + params.my_module_id = $('.my-modules-protocols-index').data('task-id'); + } $.ajax({ method: 'GET', url: that.attr('href'), + data: params, dataType: 'json' }).done(function(xhr, settings, data) { if ($('#modal-info-repository-row').length) { @@ -16,6 +21,7 @@ $('.modal-backdrop').remove(); } $('body').append($.parseHTML(data.responseJSON.html)); + $('[data-toggle="tooltip"]').tooltip(); $('#modal-info-repository-row').modal('show', { backdrop: true, keyboard: false @@ -73,4 +79,27 @@ } } }); + + $(document).on('click', '.assign-inventory-button', function(e) { + e.preventDefault(); + let assignUrl = $(this).data('assignUrl'); + let repositoryRowId = $(this).data('repositoryRowId'); + + $.ajax({ + url: assignUrl, + type: 'POST', + data: { repository_row_id: repositoryRowId }, + dataType: 'json', + success: function(data) { + HelperModule.flashAlertMsg(data.flash, 'success'); + $('#modal-info-repository-row').modal('hide'); + if (typeof MyModuleRepositories !== 'undefined') { + MyModuleRepositories.reloadRepositoriesList(repositoryRowId); + } + }, + error: function(error) { + HelperModule.flashAlertMsg(error.responseJSON.flash, 'danger'); + } + }); + }); }()); diff --git a/app/assets/stylesheets/repository/assign_items_to_task_modal.scss b/app/assets/stylesheets/repository/assign_items_to_task_modal.scss new file mode 100644 index 000000000..dedd7be94 --- /dev/null +++ b/app/assets/stylesheets/repository/assign_items_to_task_modal.scss @@ -0,0 +1,38 @@ +.assign-items-to-task-modal-container { + .modal-header { + color: $color-volcano; + display: flex; + font-size: $font-size-h2; + font-weight: bold; + padding: 1rem; + + .close { + margin-left: auto; + } + } + + .modal-body { + color: $color-volcano; + display: flex; + flex-direction: column; + font-size: $font-size-base; + row-gap: 1rem; + + .level-selector { + display: flex; + flex-direction: column; + row-gap: .25rem; + + } + + label { + font-size: $font-size-h6; + font-weight: bold; + margin-bottom: 0; + } + } + + .modal-footer { + padding: 1rem; + } +} diff --git a/app/assets/stylesheets/repository/repository_row_modal.scss b/app/assets/stylesheets/repository/repository_row_modal.scss index a25126b89..3399f7ec9 100644 --- a/app/assets/stylesheets/repository/repository_row_modal.scss +++ b/app/assets/stylesheets/repository/repository_row_modal.scss @@ -3,4 +3,15 @@ display: flex; justify-content: flex-end; } + + .modal-footer[data-assign-item-button="true"] { + align-items: center; + display: flex; + gap: .5em; + width: 100%; + + .print-label-button { + margin-right: auto; + } + } } diff --git a/app/assets/stylesheets/shared/select.scss b/app/assets/stylesheets/shared/select.scss index f31a78c6a..69195c5f9 100644 --- a/app/assets/stylesheets/shared/select.scss +++ b/app/assets/stylesheets/shared/select.scss @@ -83,7 +83,6 @@ max-height: 300px; overflow: hidden; overflow-y: scroll; - position: absolute; top: 2.5em; width: 100%; z-index: 9999; diff --git a/app/assets/stylesheets/shared/smart_annotation.scss b/app/assets/stylesheets/shared/smart_annotation.scss index 7cdb403c6..2faedd274 100644 --- a/app/assets/stylesheets/shared/smart_annotation.scss +++ b/app/assets/stylesheets/shared/smart_annotation.scss @@ -1,3 +1,6 @@ +// scss-lint:disable SelectorDepth +// scss-lint:disable NestingDepth + .atwho-view { background: $color_white; border-radius: $border-radius-default; @@ -107,15 +110,49 @@ .item { cursor: pointer; - margin-left: -.5em; + line-height: 2.25em; overflow: hidden; - padding: .25em .5em; + padding: 0 .5em; + position: relative; text-overflow: ellipsis; - width: calc(100% + 1em); + vertical-align: middle; white-space: nowrap; + width: 100%; + + .atwho-button-container { + background: linear-gradient(90deg, + transparent, + $color-concrete 15%, + $color-concrete 100%); + display: inline; + opacity: 0; + padding-left: 2em; + position: absolute; + right: 0; + + .atwho-assign-button-form { + display: inline; + } + + .atwho-insert-button, + .atwho-assign-button { + background: $color-concrete; + color: $brand-primary; + height: 2.25em; + margin-right: .5em; + padding: 0 .5em; + text-align: center; + width: auto; + } + } &.cur { background: $color-concrete; + color: $brand-primary; + + .atwho-button-container { + opacity: 1; + } } .atwho-highlight { diff --git a/app/controllers/at_who_controller.rb b/app/controllers/at_who_controller.rb index 6c01dc05a..892889aa2 100644 --- a/app/controllers/at_who_controller.rb +++ b/app/controllers/at_who_controller.rb @@ -40,7 +40,7 @@ class AtWhoController < ApplicationController end if repository && can_read_repository?(repository) items = SmartAnnotation.new(current_user, current_team, @query) - .repository_rows(repository) + .repository_rows(repository, params[:assignable_my_module_id]) repository_id = repository.id else items = [] @@ -51,7 +51,7 @@ class AtWhoController < ApplicationController render json: { res: [ render_to_string(partial: 'shared/smart_annotation/repository_items.html.erb', - locals: { repository_rows: items }) + locals: { repository_rows: items, repository: repository }) ], repository: repository_id, team: current_team.id diff --git a/app/controllers/experiments_controller.rb b/app/controllers/experiments_controller.rb index 4ecd67f60..d0c77e685 100644 --- a/app/controllers/experiments_controller.rb +++ b/app/controllers/experiments_controller.rb @@ -9,8 +9,9 @@ class ExperimentsController < ApplicationController include Breadcrumbs before_action :load_project, only: %i(new create archive_group restore_group) - before_action :load_experiment, except: %i(new create archive_group restore_group actions_toolbar) - before_action :check_read_permissions, except: %i(edit archive clone move new create archive_group restore_group actions_toolbar) + before_action :load_experiment, except: %i(new create archive_group restore_group experiment_filter actions_toolbar) + before_action :check_read_permissions, except: %i(edit archive clone move new create + archive_group restore_group experiment_filter actions_toolbar) before_action :check_canvas_read_permissions, only: %i(canvas) before_action :check_create_permissions, only: %i(new create) before_action :check_manage_permissions, only: %i(edit batch_clone_my_modules) @@ -433,6 +434,20 @@ class ExperimentsController < ApplicationController end end + def experiment_filter + project = Project.readable_by_user(current_user).find_by(id: params[:project_id]) + return render_404 if project.blank? + + experiments = project.experiments + .readable_by_user(current_user) + .search(current_user, false, params[:query], 1, current_team) + .pluck(:id, :name) + + return render plain: [].to_json if experiments.blank? + + render json: experiments + end + def actions_dropdown if stale?([@experiment, @experiment.project]) render json: { diff --git a/app/controllers/my_module_repositories_controller.rb b/app/controllers/my_module_repositories_controller.rb index 5b5bee11f..5a1258762 100644 --- a/app/controllers/my_module_repositories_controller.rb +++ b/app/controllers/my_module_repositories_controller.rb @@ -4,11 +4,11 @@ class MyModuleRepositoriesController < ApplicationController include ApplicationHelper before_action :load_my_module - before_action :load_repository, except: %i(repositories_dropdown_list repositories_list_html) + before_action :load_repository, except: %i(repositories_dropdown_list repositories_list_html create) before_action :check_my_module_view_permissions, except: %i(update consume_modal update_consumption) - before_action :check_repository_view_permissions, except: %i(repositories_dropdown_list repositories_list_html) + before_action :check_repository_view_permissions, except: %i(repositories_dropdown_list repositories_list_html create) before_action :check_repository_row_consumption_permissions, only: %i(consume_modal update_consumption) - before_action :check_assign_repository_records_permissions, only: :update + before_action :check_assign_repository_records_permissions, only: %i(update create) def index_dt @draw = params[:draw].to_i @@ -41,6 +41,34 @@ class MyModuleRepositoriesController < ApplicationController render rows_view end + def create + repository_row = RepositoryRow.find(params[:repository_row_id]) + repository = repository_row.repository + return render_403 unless can_read_repository?(repository) + + ActiveRecord::Base.transaction do + @my_module.my_module_repository_rows.create!(repository_row: repository_row, assigned_by: current_user) + + Activities::CreateActivityService.call(activity_type: :assign_repository_record, + owner: current_user, + team: @my_module.experiment.project.team, + project: @my_module.experiment.project, + subject: @my_module, + message_items: { my_module: @my_module.id, + repository: repository.id, + record_names: repository_row.name }) + + render json: { + flash: t('my_modules.assigned_items.direct_assign.success') + } + end + rescue StandardError => e + Rails.logger.error e.message + render json: { + flash: t('my_modules.repository.flash.update_error') + }, status: :bad_request + end + def update service = RepositoryRows::MyModuleAssignUnassignService.call(my_module: @my_module, repository: @repository, diff --git a/app/controllers/my_modules_controller.rb b/app/controllers/my_modules_controller.rb index 959b1592c..19a2e415a 100644 --- a/app/controllers/my_modules_controller.rb +++ b/app/controllers/my_modules_controller.rb @@ -8,14 +8,14 @@ class MyModulesController < ApplicationController include MyModulesHelper include Breadcrumbs - before_action :load_vars, except: %i(restore_group create new save_table_state actions_toolbar) + before_action :load_vars, except: %i(restore_group create new save_table_state my_module_filter actions_toolbar) before_action :load_experiment, only: %i(create new) before_action :check_create_permissions, only: %i(new create) before_action :check_archive_permissions, only: %i(update) before_action :check_manage_permissions, only: %i( description due_date update_description update_protocol_description update_protocol ) - before_action :check_read_permissions, except: %i(create new update update_description + before_action :check_read_permissions, except: %i(create new update update_description my_module_filter update_protocol_description restore_group save_table_state actions_toolbar) before_action :check_update_state_permissions, only: :update_state @@ -456,6 +456,20 @@ class MyModulesController < ApplicationController render json: { provisioning_status: @my_module.provisioning_status } end + def my_module_filter + experiment = Experiment.readable_by_user(current_user).find_by(id: params[:experiment_id]) + return render_404 if experiment.blank? + + my_modules = experiment.my_modules + .readable_by_user(current_user) + .search(current_user, false, params[:query], 1, current_team) + .pluck(:id, :name) + + return render plain: [].to_json if my_modules.blank? + + render json: my_modules + end + private def load_vars diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index dcdb02ef3..e45eda1fc 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -17,7 +17,7 @@ class ProjectsController < ApplicationController sidebar experiments_cards view_type actions_dropdown create_tag) before_action :load_current_folder, only: %i(index cards new show) before_action :check_view_permissions, except: %i(index cards new create edit update archive_group restore_group - users_filter actions_dropdown actions_toolbar) + users_filter actions_dropdown project_filter actions_toolbar) before_action :check_create_permissions, only: %i(new create) before_action :check_manage_permissions, only: :edit before_action :load_exp_sort_var, only: :show @@ -104,6 +104,16 @@ class ProjectsController < ApplicationController } end + def project_filter + projects = Project.readable_by_user(current_user) + .search(current_user, false, params[:query], 1, current_team) + .pluck(:id, :name) + + return render plain: [].to_json if projects.blank? + + render json: projects + end + def new @project = current_team.projects.new(project_folder: current_folder) respond_to do |format| diff --git a/app/controllers/repository_rows_controller.rb b/app/controllers/repository_rows_controller.rb index cec9100d9..9e3c04ccb 100644 --- a/app/controllers/repository_rows_controller.rb +++ b/app/controllers/repository_rows_controller.rb @@ -64,9 +64,19 @@ class RepositoryRowsController < ApplicationController def show @repository_row = RepositoryRow.find_by(id: params[:id]) + @my_module = MyModule.find_by(id: params[:my_module_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) + return render_403 if @my_module && !can_read_my_module?(@my_module) + + if @my_module + @my_module_assign_error = if !can_assign_my_module_repository_rows?(@my_module) + I18n.t('repository_row.modal_info.assign_to_task_error.no_access') + elsif @repository_row.my_modules.where(id: @my_module.id).any? + I18n.t('repository_row.modal_info.assign_to_task_error.already_assigned') + end + end @assigned_modules = @repository_row.my_modules.joins(experiment: :project) @viewable_modules = @assigned_modules.viewable_by_user(current_user, current_user.teams) diff --git a/app/javascript/packs/tiny_mce.js b/app/javascript/packs/tiny_mce.js index 8917a3479..863454cb4 100644 --- a/app/javascript/packs/tiny_mce.js +++ b/app/javascript/packs/tiny_mce.js @@ -377,7 +377,7 @@ window.TinyMCE = (() => { editor.selection.select(editor.getBody(), true); editor.selection.collapse(false); - SmartAnnotation.init($(editor.contentDocument.activeElement)); + SmartAnnotation.init($(editor.contentDocument.activeElement), false, options.assignableMyModuleId); SmartAnnotation.preventPropagation('.atwho-user-popover'); if (options.afterInitCallback) { options.afterInitCallback(); } diff --git a/app/javascript/packs/vue/assign_items_to_task_modal.js b/app/javascript/packs/vue/assign_items_to_task_modal.js new file mode 100644 index 000000000..7fd3cbc50 --- /dev/null +++ b/app/javascript/packs/vue/assign_items_to_task_modal.js @@ -0,0 +1,37 @@ +import TurbolinksAdapter from 'vue-turbolinks'; +import Vue from 'vue/dist/vue.esm'; +import AssignItemsToTaskModalContainer from '../../vue/assign_items_to_tasks_modal/container.vue'; + +Vue.use(TurbolinksAdapter); +Vue.prototype.i18n = window.I18n; + +function initAssignItemsToTaskModalComponent() { + const container = $('.assign-items-to-task-modal-container'); + if (container.length) { + window.AssignItemsToTaskModalComponentContainer = new Vue({ + el: '.assign-items-to-task-modal-container', + name: 'AssignItemsToTaskModalComponent', + components: { + 'assign-items-to-task-modal-container': AssignItemsToTaskModalContainer + }, + data() { + return { + visibility: false, + urls: { + assign: container.data('assign-url'), + projects: container.data('projects-url'), + experiments: container.data('experiments-url'), + tasks: container.data('tasks-url') + } + }; + }, + methods: { + closeModal() { + this.visibility = false; + } + } + }); + } +} + +initAssignItemsToTaskModalComponent(); diff --git a/app/javascript/vue/assign_items_to_tasks_modal/container.vue b/app/javascript/vue/assign_items_to_tasks_modal/container.vue new file mode 100644 index 000000000..fc266fc9d --- /dev/null +++ b/app/javascript/vue/assign_items_to_tasks_modal/container.vue @@ -0,0 +1,290 @@ + + + diff --git a/app/javascript/vue/protocol/container.vue b/app/javascript/vue/protocol/container.vue index c32a910f3..f98c61746 100644 --- a/app/javascript/vue/protocol/container.vue +++ b/app/javascript/vue/protocol/container.vue @@ -76,6 +76,7 @@ :objectId="parseInt(protocol.id)" :fieldName="'protocol[description]'" :lastUpdated="protocol.attributes.updated_at" + :assignableMyModuleId="protocol.attributes.assignable_my_module_id" :characterLimit="1000000" @update="updateDescription" /> @@ -136,6 +137,7 @@ @stepUpdated="refreshProtocolStatus" @step:insert="updateStepsPosition" :reorderStepUrl="steps.length > 1 ? urls.reorder_steps_url : null" + :assignableMyModuleId="protocol.attributes.assignable_my_module_id" /> diff --git a/app/javascript/vue/protocol/step.vue b/app/javascript/vue/protocol/step.vue index b0b10ba33..28e9603ad 100644 --- a/app/javascript/vue/protocol/step.vue +++ b/app/javascript/vue/protocol/step.vue @@ -136,6 +136,7 @@ :element.sync="elements[index]" :inRepository="inRepository" :reorderElementUrl="elements.length > 1 ? urls.reorder_elements_url : ''" + :assignableMyModuleId="assignableMyModuleId" :isNew="element.isNew" @component:delete="deleteElement" @update="updateElement" @@ -213,6 +214,10 @@ }, reorderStepUrl: { required: false + }, + assignableMyModuleId: { + type: Number, + required: false } }, data() { diff --git a/app/javascript/vue/protocol/step_elements/checklist.vue b/app/javascript/vue/protocol/step_elements/checklist.vue index 47f87571b..03d07a818 100644 --- a/app/javascript/vue/protocol/step_elements/checklist.vue +++ b/app/javascript/vue/protocol/step_elements/checklist.vue @@ -104,6 +104,10 @@ isNew: { type: Boolean, default: false + }, + assignableMyModuleId: { + type: Number, + required: false } }, data() { diff --git a/app/javascript/vue/protocol/step_elements/table.vue b/app/javascript/vue/protocol/step_elements/table.vue index 3c92349f5..2a369f9f6 100644 --- a/app/javascript/vue/protocol/step_elements/table.vue +++ b/app/javascript/vue/protocol/step_elements/table.vue @@ -83,6 +83,10 @@ }, isNew: { type: Boolean, default: false + }, + assignableMyModuleId: { + type: Number, + required: false } }, data() { diff --git a/app/javascript/vue/protocol/step_elements/text.vue b/app/javascript/vue/protocol/step_elements/text.vue index 4c6f06242..396d11699 100644 --- a/app/javascript/vue/protocol/step_elements/text.vue +++ b/app/javascript/vue/protocol/step_elements/text.vue @@ -26,6 +26,7 @@ :objectId="element.attributes.orderable.id" :fieldName="'step_text[text]'" :lastUpdated="element.attributes.orderable.updated_at" + :assignableMyModuleId="assignableMyModuleId" :characterLimit="1000000" @update="update" @editingDisabled="disableEditMode" @@ -64,6 +65,10 @@ isNew: { type: Boolean, default: false + }, + assignableMyModuleId: { + type: Number, + required: false } }, data() { diff --git a/app/javascript/vue/shared/inline_edit.vue b/app/javascript/vue/shared/inline_edit.vue index 6ba45790c..d624f096c 100644 --- a/app/javascript/vue/shared/inline_edit.vue +++ b/app/javascript/vue/shared/inline_edit.vue @@ -144,7 +144,7 @@ this.$refs.input.select(); } if (this.smartAnnotation) { - SmartAnnotation.init($(this.$refs.input)); + SmartAnnotation.init($(this.$refs.input), false); } }) this.$emit('editingEnabled'); diff --git a/app/javascript/vue/shared/select.vue b/app/javascript/vue/shared/select.vue index 9cb048dfa..8a3862184 100644 --- a/app/javascript/vue/shared/select.vue +++ b/app/javascript/vue/shared/select.vue @@ -48,7 +48,7 @@ setTimeout(() => { this.isOpen = false; this.$emit('blur'); - }, 100) + }, 200) }, toggle() { this.isOpen = !this.isOpen; @@ -70,10 +70,19 @@ this.$emit('change', this.value); }, updateOptionPosition() { - let rect = this.$refs.container.getBoundingClientRect(); - let top =rect.top + rect.height; - let left = rect.left; + const container = this.$refs.container; + const rect = container.getBoundingClientRect(); let width = rect.width; + let top = rect.top + rect.height; + let left = rect.left; + + const modal = $(container).parents('.modal-content'); + + if (modal.length > 0) { + const modalRect = modal.get(0).getBoundingClientRect(); + top -= modalRect.top; + left -= modalRect.left; + } this.optionPositionStyle = `position: fixed; top: ${top}px; left: ${left}px; width: ${width}px` } diff --git a/app/javascript/vue/shared/select_search.vue b/app/javascript/vue/shared/select_search.vue index 44827b109..88249ef97 100644 --- a/app/javascript/vue/shared/select_search.vue +++ b/app/javascript/vue/shared/select_search.vue @@ -1,5 +1,5 @@