diff --git a/app/assets/javascripts/repositories/repository_datatable.js b/app/assets/javascripts/repositories/repository_datatable.js index 2752c903f..4d0a6652a 100644 --- a/app/assets/javascripts/repositories/repository_datatable.js +++ b/app/assets/javascripts/repositories/repository_datatable.js @@ -1,6 +1,6 @@ /* globals I18n _ SmartAnnotation FilePreviewModal animateSpinner Promise DataTableHelpers - HelperModule animateLoading hideAssignUnasignModal RepositoryDatatableRowEditor + HelperModule animateLoading RepositoryDatatableRowEditor initAssignedTasksDropdown */ @@ -15,7 +15,8 @@ var RepositoryDatatable = (function(global) { var TABLE_WRAPPER_ID = '.repository-table'; var TABLE = null; var EDITABLE = false; - var SELECT_ALL_SELECTOR = "#checkbox > input[name=select_all]" + var SELECT_ALL_SELECTOR = '#checkbox > input[name=select_all]'; + const STATUS_POLLING_INTERVAL = 10000; var rowsSelected = []; var rowsLocked = []; @@ -266,6 +267,12 @@ var RepositoryDatatable = (function(global) { if ($('#assigned').text().length === 0) { TABLE.column(1).visible(false); } + + $.getJSON($(TABLE_ID).data('toolbar-url'), (data) => { + $('#toolbarButtonsDatatable').remove(); + $(data.html).appendTo('div.toolbar'); + }); + TABLE.ajax.reload(null, false); changeToViewMode(); SmartAnnotation.closePopup(); @@ -399,6 +406,18 @@ var RepositoryDatatable = (function(global) { }); } + function checkSnapshottingStatus() { + $.getJSON($(TABLE_ID).data('status-url'), (statusData) => { + if (statusData.snapshot_provisioning) { + setTimeout(() => { checkSnapshottingStatus(); }, STATUS_POLLING_INTERVAL); + } else { + EDITABLE = statusData.editable; + $('.repository-provisioning-notice').remove(); + resetTableView(); + } + }); + } + function dataTableInit() { viewAssigned = 'assigned'; TABLE = $(TABLE_ID).DataTable({ @@ -512,8 +531,10 @@ var RepositoryDatatable = (function(global) { changeToViewMode(); updateDataTableSelectAllCtrl(); FilePreviewModal.init(); + // Prevent row toggling when selecting user smart annotation link SmartAnnotation.preventPropagation('.atwho-user-popover'); + // Show number of selected rows near pages info $('#repository-table_info').append(''); $('#selected_info').html(' (' + rowsSelected.length + ' entries selected)'); @@ -547,15 +568,15 @@ var RepositoryDatatable = (function(global) { }); }, fnInitComplete: function() { - disableCheckboxToggleOnAssetDownload(); FilePreviewModal.init(); initHeaderTooltip(); disableCheckboxToggleOnCheckboxPreview(); - // Append button to inner toolbar in table - $('div.toolbarButtonsDatatable').appendTo('div.toolbar'); - $('div.toolbarButtonsDatatable').show(); + // Append buttons to inner toolbar in the table + $.getJSON($(TABLE_ID).data('toolbar-url'), (data) => { + $(data.html).appendTo('div.toolbar'); + }); $('div.toolbar-filter-buttons').prependTo('div.filter-container'); $('div.toolbar-filter-buttons').show(); @@ -564,12 +585,10 @@ var RepositoryDatatable = (function(global) { $('div.toolbarButtons').appendTo('div.toolbar'); $('div.toolbarButtons').show(); - if (EDITABLE) { - RepositoryDatatableRowEditor.initFormSubmitAction(TABLE); - initItemEditIcon(); - initSaveButton(); - initCancelButton(); - } + RepositoryDatatableRowEditor.initFormSubmitAction(TABLE); + initItemEditIcon(); + initSaveButton(); + initCancelButton(); DataTableHelpers.initLengthApearance($(TABLE_ID).closest('.dataTables_wrapper')); DataTableHelpers.initSearchField($(TABLE_ID).closest('.dataTables_wrapper')); @@ -664,28 +683,6 @@ var RepositoryDatatable = (function(global) { ); }; - global.submitUnassignRepositoryRecord = function(option) { - animateSpinner(); - $.ajax({ - url: $('#unassignRepositoryRecordModal').data('unassign-url'), - type: 'POST', - dataType: 'json', - data: { selected_rows: rowsSelected, downstream: (option === 'downstream') }, - success: function(data) { - hideAssignUnasignModal('#unassignRepositoryRecordModal'); - HelperModule.flashAlertMsg(data.flash, 'success'); - resetTableView(); - clearRowSelection(); - }, - error: function(data) { - hideAssignUnasignModal('#unassignRepositoryRecordModal'); - HelperModule.flashAlertMsg(data.responseJSON.flash, 'danger'); - resetTableView(); - clearRowSelection(); - } - }); - } - global.onClickDeleteRecord = function() { animateSpinner(); $.ajax({ @@ -780,6 +777,9 @@ var RepositoryDatatable = (function(global) { TABLE_ID = id; EDITABLE = $(TABLE_ID).data('editable'); TABLE = dataTableInit(); + if ($(TABLE_ID).data('snapshot-provisioning')) { + setTimeout(() => { checkSnapshottingStatus(); }, STATUS_POLLING_INTERVAL); + } } function destroy() { diff --git a/app/assets/javascripts/repositories/row_editor.js b/app/assets/javascripts/repositories/row_editor.js index 7534e987e..aef9c6381 100644 --- a/app/assets/javascripts/repositories/row_editor.js +++ b/app/assets/javascripts/repositories/row_editor.js @@ -105,7 +105,7 @@ var RepositoryDatatableRowEditor = (function() { TABLE.ajax.reload(() => { animateSpinner(null, false); HelperModule.flashAlertMsg(data.flash, 'success'); - $('html, body').animate({scrollLeft: 0}, 300); + $('html, body').animate({ scrollLeft: 0 }, 300); }); }); diff --git a/app/assets/javascripts/repository_columns/index.js b/app/assets/javascripts/repository_columns/index.js index a800b9e25..e6f270bbc 100644 --- a/app/assets/javascripts/repository_columns/index.js +++ b/app/assets/javascripts/repository_columns/index.js @@ -21,9 +21,6 @@ var RepositoryColumns = (function() { function reloadDataTablePartial() { // Append buttons for inventory datatable - $('div.toolbarButtonsDatatable').appendTo('.repository-show'); - $('div.toolbarButtonsDatatable').hide(); - $('div.toolbar-filter-buttons').appendTo('.repository-show'); $('div.toolbar-filter-buttons').hide(); diff --git a/app/assets/stylesheets/repositories.scss b/app/assets/stylesheets/repositories.scss index b4a1b741d..478e9e526 100644 --- a/app/assets/stylesheets/repositories.scss +++ b/app/assets/stylesheets/repositories.scss @@ -116,6 +116,10 @@ float: right; } } + + .repository-provisioning-notice { + color: $brand-info; + } } .dataTables_scroll { @@ -350,7 +354,7 @@ } } -.toolbarButtonsDatatable { +#toolbarButtonsDatatable { .view-only-label { opacity: .6; } diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 3c7fbfc16..9e0eb9f42 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -8,19 +8,14 @@ class RepositoriesController < ApplicationController include TeamsHelper before_action :switch_team_with_param, only: :show - before_action :load_vars, - except: %i(index create create_modal parse_sheet) - before_action :load_parent_vars, except: - %i(repository_table_index parse_sheet) + before_action :load_repository, except: %i(index create create_modal) + before_action :load_repositories, only: %i(index show) before_action :check_view_all_permissions, only: :index - before_action :check_view_permissions, only: %i(load_table export_repository show) - before_action :check_manage_permissions, only: - %i(destroy destroy_modal rename_modal update) + before_action :check_view_permissions, except: %i(index create_modal create update destroy parse_sheet import_records) + before_action :check_manage_permissions, only: %i(destroy destroy_modal rename_modal update) before_action :check_share_permissions, only: :share_modal - before_action :check_create_permissions, only: - %i(create_modal create) - before_action :check_copy_permissions, only: - %i(copy_modal copy) + before_action :check_create_permissions, only: %i(create_modal create) + before_action :check_copy_permissions, only: %i(copy_modal copy) before_action :set_inline_name_editing, only: %i(show) layout 'fluid' @@ -34,6 +29,20 @@ class RepositoriesController < ApplicationController @display_edit_button = can_create_repository_rows?(@repository) @display_delete_button = can_delete_repository_rows?(@repository) @display_duplicate_button = can_create_repository_rows?(@repository) + @snapshot_provisioning = @repository.repository_snapshots.provisioning.any? + end + + def table_toolbar + render json: { + html: render_to_string(partial: 'repositories/toolbar_buttons.html.erb') + } + end + + def status + render json: { + editable: can_manage_repository_rows?(@repository), + snapshot_provisioning: @repository.repository_snapshots.provisioning.any? + } end def load_table @@ -69,7 +78,7 @@ class RepositoriesController < ApplicationController def create @repository = Repository.new( - team: @team, + team: current_team, created_by: current_user ) @repository.assign_attributes(repository_params) @@ -146,7 +155,7 @@ class RepositoriesController < ApplicationController def copy_modal @tmp_repository = Repository.new( - team: @team, + team: current_team, created_by: current_user, name: @repository.name ) @@ -163,7 +172,7 @@ class RepositoriesController < ApplicationController def copy @tmp_repository = Repository.new( - team: @team, + team: current_team, created_by: current_user ) @tmp_repository.assign_attributes(repository_params) @@ -196,25 +205,15 @@ class RepositoriesController < ApplicationController # AJAX actions def repository_table_index - if @repository.nil? || !can_read_repository?(@repository) - render_403 - else - respond_to do |format| - format.html - format.json do - render json: ::RepositoryDatatable.new(view_context, - @repository, - nil, - current_user) - end + respond_to do |format| + format.json do + render json: ::RepositoryDatatable.new(view_context, @repository, nil, current_user) end end end def parse_sheet - repository = Repository.accessible_by_teams(current_team).find_by_id(import_params[:id]) - - render_403 unless can_create_repository_rows?(repository) + render_403 unless can_create_repository_rows?(@repository) unless import_params[:file] repository_response(t('teams.parse_sheet.errors.no_file_selected')) @@ -223,7 +222,7 @@ class RepositoriesController < ApplicationController begin parsed_file = ImportRepository::ParseRepository.new( file: import_params[:file], - repository: repository, + repository: @repository, session: session ) if parsed_file.too_large? @@ -330,16 +329,14 @@ class RepositoriesController < ApplicationController ) end - def load_vars + def load_repository repository_id = params[:id] || params[:repository_id] - @repository = Repository.accessible_by_teams(current_team).find_by_id(repository_id) + @repository = Repository.accessible_by_teams(current_team).find_by(id: repository_id) render_404 unless @repository end - def load_parent_vars - @team = current_team - render_404 unless @team - @repositories = Repository.accessible_by_teams(@team).order('repositories.created_at ASC') + def load_repositories + @repositories = Repository.accessible_by_teams(current_team).order('repositories.created_at ASC') end def set_inline_name_editing @@ -356,7 +353,7 @@ class RepositoriesController < ApplicationController end def check_view_all_permissions - render_403 unless can_read_team?(@team) + render_403 unless can_read_team?(current_team) end def check_view_permissions @@ -364,11 +361,11 @@ class RepositoriesController < ApplicationController end def check_create_permissions - render_403 unless can_create_repositories?(@team) + render_403 unless can_create_repositories?(current_team) end def check_copy_permissions - render_403 if !can_create_repositories?(@team) || @repository.shared_with?(current_team) + render_403 if !can_create_repositories?(current_team) || @repository.shared_with?(current_team) end def check_manage_permissions @@ -407,7 +404,7 @@ class RepositoriesController < ApplicationController .call(activity_type: type_of, owner: current_user, subject: @repository, - team: @team, + team: current_team, message_items: message_items) end end diff --git a/app/controllers/repository_rows_controller.rb b/app/controllers/repository_rows_controller.rb index 79f9ad8c4..dce0099d5 100644 --- a/app/controllers/repository_rows_controller.rb +++ b/app/controllers/repository_rows_controller.rb @@ -4,18 +4,13 @@ class RepositoryRowsController < ApplicationController include ApplicationHelper include MyModulesHelper - before_action :load_info_modal_vars, only: %i(show assigned_task_list) - before_action :load_vars, only: %i(edit update) - before_action :load_repository, - only: %i(create - delete_records - index - copy_records - available_rows) + 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 :check_snapshotting_status, only: %i(create update delete_records copy_records) before_action :check_create_permissions, only: :create before_action :check_delete_permissions, only: :delete_records - before_action :check_manage_permissions, - only: %i(edit update copy_records) + before_action :check_manage_permissions, only: %i(update copy_records) def index @draw = params[:draw].to_i @@ -54,6 +49,9 @@ class RepositoryRowsController < ApplicationController end def show + @assigned_modules = MyModuleRepositoryRow.eager_load(my_module: [{ experiment: :project }]) + .where(repository_row: @repository_row) + respond_to do |format| format.json do render json: { @@ -65,54 +63,26 @@ class RepositoryRowsController < ApplicationController end end - def edit - json = { - repository_row: { - name: escape_input(@record.name), - repository_cells: {}, - repository_column_items: fetch_columns_list_items - } - } - - # Add custom cells ids as key (easier lookup on js side) - @record.repository_cells.each do |cell| - if cell.value_type == 'RepositoryAssetValue' - cell_value = cell.value.asset - else - cell_value = escape_input(cell.value.data) - end - - json[:repository_row][:repository_cells][cell.repository_column_id] = { - repository_cell_id: cell.id, - cell_column_id: cell.repository_column.id, # needed for mappings - value: cell_value, - type: cell.value_type, - list_items: fetch_list_items(cell) - } - end - - respond_to do |format| - format.html - format.json { render json: json } - end - end - def update row_update = RepositoryRows::UpdateRepositoryRowService - .call(repository_row: @record, user: current_user, params: update_params) + .call(repository_row: @repository_row, user: current_user, params: update_params) if row_update.succeed? if row_update.record_updated - log_activity(:edit_item_inventory, @record) - @record.repository_cells.where(value_type: 'RepositoryTextValue').each do |repository_cell| - record_annotation_notification(@record, repository_cell) + log_activity(:edit_item_inventory, @repository_row) + @repository_row.repository_cells.where(value_type: 'RepositoryTextValue').each do |repository_cell| + record_annotation_notification(@repository_row, repository_cell) end end - render json: { id: @record.id, flash: t('repositories.update.success_flash', - record: escape_input(@record.name), - repository: escape_input(@repository.name)) }, - status: :ok + render json: { + id: @repository_row.id, + flash: t( + 'repositories.update.success_flash', + record: escape_input(@repository_row.name), + repository: escape_input(@repository.name) + ) + }, status: :ok else render json: row_update.errors, status: :bad_request end @@ -122,7 +92,7 @@ class RepositoryRowsController < ApplicationController deleted_count = 0 if selected_params selected_params.each do |row_id| - row = @repository.repository_rows.find_by_id(row_id) + row = @repository.repository_rows.find_by(id: row_id) next unless row && can_manage_repository_rows?(@repository) log_activity(:delete_item_inventory, row) @@ -196,33 +166,34 @@ class RepositoryRowsController < ApplicationController include StringUtility AvailableRepositoryRow = Struct.new(:id, :name, :has_file_attached) - def load_info_modal_vars - @repository_row = RepositoryRow.eager_load(:created_by, repository: [:team]) - .find_by_id(params[:id]) - @assigned_modules = MyModuleRepositoryRow.eager_load( - my_module: [{ experiment: :project }] - ).where(repository_row: @repository_row) - render_404 and return unless @repository_row - render_403 unless can_read_repository?(@repository_row.repository) - end - - def load_vars + def load_repository @repository = Repository.accessible_by_teams(current_team) .eager_load(:repository_columns) - .find_by_id(params[:repository_id]) - - @record = @repository.repository_rows - .eager_load(:repository_columns) - .find_by_id(params[:id]) - render_404 unless @repository && @record + .find_by(id: params[:repository_id]) + render_404 unless @repository end - def load_repository - @repository = Repository.accessible_by_teams(current_team).find_by_id(params[:repository_id]) - render_404 unless @repository + def load_repository_row + @repository_row = @repository.repository_rows.eager_load(:repository_columns).find_by(id: params[:id]) + render_404 unless @repository_row + end + + def check_read_permissions render_403 unless can_read_repository?(@repository) end + def check_snapshotting_status + return if @repository.repository_snapshots.provisioning.none? + + respond_to do |format| + format.json do + render json: { + flash: t('repositories.index.snapshot_provisioning_in_progress') + }, status: :unprocessable_entity + end + end + end + def check_create_permissions render_403 unless can_create_repository_rows?(@repository) end diff --git a/app/helpers/repository_datatable_helper.rb b/app/helpers/repository_datatable_helper.rb index b4a05bc9b..f372add22 100644 --- a/app/helpers/repository_datatable_helper.rb +++ b/app/helpers/repository_datatable_helper.rb @@ -18,11 +18,6 @@ module RepositoryDatatableHelper unless options[:view_mode] row.merge!( - 'recordEditUrl': Rails.application.routes.url_helpers - .edit_repository_repository_row_path( - repository, - record.id - ), 'recordUpdateUrl': Rails.application.routes.url_helpers .repository_repository_row_path( repository, diff --git a/app/permissions/repository.rb b/app/permissions/repository.rb index 55a97b48d..8b578e3e2 100644 --- a/app/permissions/repository.rb +++ b/app/permissions/repository.rb @@ -12,6 +12,19 @@ Canaid::Permissions.register_for(RepositoryBase) do end Canaid::Permissions.register_for(Repository) do + # Should be no provisioning snapshots for repository for all the specified permissions + %i(manage_repository + create_repository_rows + manage_repository_rows + update_repository_rows + delete_repository_rows + create_repository_columns) + .each do |perm| + can perm do |_, repository| + repository.repository_snapshots.provisioning.none? + end + end + # repository: update, delete can :manage_repository do |user, repository| user.is_admin_of_team?(repository.team) unless repository.shared_with?(user.current_team) diff --git a/app/permissions/repository_column.rb b/app/permissions/repository_column.rb index b1af4ecf3..3669014cb 100644 --- a/app/permissions/repository_column.rb +++ b/app/permissions/repository_column.rb @@ -4,6 +4,7 @@ Canaid::Permissions.register_for(RepositoryColumn) do # repository: update/delete field # Tested in scope of RepositoryPermissions spec can :manage_repository_column do |user, repository_column| - can_create_repository_columns?(user, repository_column.repository) + repository_column.repository.repository_snapshots.provisioning.none? && + can_create_repository_columns?(user, repository_column.repository) end end diff --git a/app/services/repository_columns/update_column_service.rb b/app/services/repository_columns/update_column_service.rb index 1b1f3d194..69dc9d78d 100644 --- a/app/services/repository_columns/update_column_service.rb +++ b/app/services/repository_columns/update_column_service.rb @@ -25,7 +25,7 @@ module RepositoryColumns def column_attributes @params[:repository_status_items_attributes]&.map do |m| # assign for new records only - m.merge!(repository_id: @repository.id, created_by_id: @user.id, last_modified_by_id: @user.id) unless m[:id] + m.merge!(created_by_id: @user.id, last_modified_by_id: @user.id) unless m[:id] end @params diff --git a/app/views/my_modules/repositories/_full_view_snapshot_table.html.erb b/app/views/my_modules/repositories/_full_view_snapshot_table.html.erb index f39e6cefc..71df469d8 100644 --- a/app/views/my_modules/repositories/_full_view_snapshot_table.html.erb +++ b/app/views/my_modules/repositories/_full_view_snapshot_table.html.erb @@ -17,7 +17,7 @@ <%= t("repositories.table.row_name") %> <%= t("repositories.table.added_on") %> <%= t("repositories.table.added_by") %> - <% @repository_snapshot.repository_columns.order(:id).each do |column| %> + <% @repository_snapshot.repository_columns.order(:parent_id).each do |column| %> - <%= bootstrap_form_for [@team, @repository], remote: :true do |f| %> + <%= bootstrap_form_for [current_team, @repository], remote: :true do |f| %>