diff --git a/app/assets/javascripts/my_modules.js b/app/assets/javascripts/my_modules.js index 940d4ed99..16016b3f0 100644 --- a/app/assets/javascripts/my_modules.js +++ b/app/assets/javascripts/my_modules.js @@ -1,6 +1,8 @@ /* global I18n dropdownSelector HelperModule animateSpinner */ /* eslint-disable no-use-before-define */ +const STATUS_POLLING_INTERVAL = 5000; + function initTaskCollapseState() { let taskView = '.my-modules-protocols-index'; let taskSection = '.task-section-caret'; @@ -236,7 +238,20 @@ function bindEditTagsAjax() { }); } +function checkStatusState() { + $.getJSON($('.status-flow-dropdown').data('status-check-url'), (statusData) => { + if (statusData.status_changing) { + setTimeout(() => { checkStatusState(); }, STATUS_POLLING_INTERVAL); + } else { + location.reload(); + } + }); +} + function applyTaskStatusChangeCallBack() { + if ($('.status-flow-dropdown').data('status-changing')) { + setTimeout(() => { checkStatusState(); }, STATUS_POLLING_INTERVAL); + } $('.task-flows').on('click', '#dropdownTaskFlowList > li[data-state-id]', function() { var list = $('#dropdownTaskFlowList'); var item = $(this); diff --git a/app/controllers/my_module_repository_snapshots_controller.rb b/app/controllers/my_module_repository_snapshots_controller.rb index 379ed0155..6360eca6d 100644 --- a/app/controllers/my_module_repository_snapshots_controller.rb +++ b/app/controllers/my_module_repository_snapshots_controller.rb @@ -31,7 +31,8 @@ class MyModuleRepositorySnapshotsController < ApplicationController end def create - repository_snapshot = @repository.provision_snapshot(@my_module, current_user) + repository_snapshot = RepositorySnapshot.create_preliminary(@repository, @my_module, current_user) + RepositorySnapshotProvisioningJob.perform_later(repository_snapshot) render json: { html: render_to_string(partial: 'my_modules/repositories/full_view_version', diff --git a/app/controllers/my_modules_controller.rb b/app/controllers/my_modules_controller.rb index 2f1d9c4ff..296d42cd1 100644 --- a/app/controllers/my_modules_controller.rb +++ b/app/controllers/my_modules_controller.rb @@ -11,8 +11,7 @@ class MyModulesController < ApplicationController before_action :load_projects_tree, only: %i(protocols results activities archive) 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) + before_action :check_view_permissions, except: %i(update update_description update_protocol_description) before_action :check_update_state_permissions, only: :update_state before_action :set_inline_name_editing, only: %i(protocols results activities archive) @@ -46,6 +45,14 @@ class MyModulesController < ApplicationController end end + def status_state + respond_to do |format| + format.json do + render json: { status_changing: @my_module.status_changing? } + end + end + end + def activities params[:subjects] = { MyModule: [@my_module.id] diff --git a/app/jobs/my_module_status_consequences_job.rb b/app/jobs/my_module_status_consequences_job.rb new file mode 100644 index 000000000..aa0a4d37c --- /dev/null +++ b/app/jobs/my_module_status_consequences_job.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class MyModuleStatusConsequencesJob < ApplicationJob + queue_as :high_priority + + def perform(my_module, my_module_status_consequences) + error_raised = false + my_module.transaction do + my_module_status_consequences.each do |consequence| + consequence.call(my_module) + end + my_module.update!(status_changing: false) + rescue StandardError => e + Rails.logger.error(e.message) + Rails.logger.error(e.backtrace.join("\n")) + error_raised = true + end + if error_raised + my_module.my_module_status = my_module.changing_from_my_module_status + my_module.status_changing = false + my_module.save! + end + end +end diff --git a/app/models/my_module.rb b/app/models/my_module.rb index 5a4c2ee31..4b135931b 100644 --- a/app/models/my_module.rb +++ b/app/models/my_module.rb @@ -27,11 +27,7 @@ class MyModule < ApplicationRecord validate :check_status, if: :my_module_status_id_changed? validate :check_status_conditions, if: :my_module_status_id_changed? validate :check_status_implications, unless: proc { |mm| - mm.my_module_status_id_changed? || - mm.x_changed? || - mm.y_changed? || - mm.my_module_group_id_changed? || - mm.workflow_order_changed? + (mm.changed_attributes.keys - %w(my_module_status_id x y my_module_group_id workflow_order status_changing)).blank? } belongs_to :created_by, @@ -53,6 +49,7 @@ class MyModule < ApplicationRecord belongs_to :experiment, inverse_of: :my_modules, touch: true belongs_to :my_module_group, inverse_of: :my_modules, optional: true belongs_to :my_module_status, optional: true + belongs_to :changing_from_my_module_status, optional: true, class_name: 'MyModuleStatus' delegate :my_module_status_flow, to: :my_module_status, allow_nil: true has_many :results, inverse_of: :my_module, dependent: :destroy has_many :my_module_tags, inverse_of: :my_module, dependent: :destroy @@ -568,10 +565,17 @@ class MyModule < ApplicationRecord end def exec_status_consequences - return if my_module_status.blank? + return if my_module_status.blank? || status_changing - my_module_status.my_module_status_consequences.each do |consequence| - consequence.call(self) + self.changing_from_my_module_status_id = my_module_status_id_was if my_module_status_id_was.present? + + if my_module_status.my_module_status_consequences.any?(&:runs_in_background?) + self.status_changing = true + MyModuleStatusConsequencesJob.perform_later(self, my_module_status.my_module_status_consequences.to_a) + else + my_module_status.my_module_status_consequences.each do |consequence| + consequence.call(self) + end end end end diff --git a/app/models/my_module_status_consequence.rb b/app/models/my_module_status_consequence.rb index 4aa31924d..5ed34193e 100644 --- a/app/models/my_module_status_consequence.rb +++ b/app/models/my_module_status_consequence.rb @@ -2,4 +2,8 @@ class MyModuleStatusConsequence < ApplicationRecord belongs_to :my_module_status + + def runs_in_background? + false + end end diff --git a/app/models/my_module_status_consequences/repository_snapshot.rb b/app/models/my_module_status_consequences/repository_snapshot.rb index 6ad7c3aec..090700f13 100644 --- a/app/models/my_module_status_consequences/repository_snapshot.rb +++ b/app/models/my_module_status_consequences/repository_snapshot.rb @@ -2,9 +2,18 @@ module MyModuleStatusConsequences class RepositorySnapshot < MyModuleStatusConsequence + def runs_in_background? + true + end + def call(my_module) my_module.assigned_repositories.each do |repository| - repository.provision_snapshot(my_module) + repository_snapshot = ::RepositorySnapshot.create_preliminary(repository, my_module) + service = Repositories::SnapshotProvisioningService.call(repository_snapshot: repository_snapshot) + unless service.succeed? + repository_snapshot.failed! + raise StandardError, service.errors + end end end end diff --git a/app/models/repository.rb b/app/models/repository.rb index 0df694b54..50e4a0c95 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -209,21 +209,6 @@ class Repository < RepositoryBase importer.run end - def provision_snapshot(my_module, created_by = nil) - created_by ||= self.created_by - repository_snapshot = dup.becomes(RepositorySnapshot) - repository_snapshot.assign_attributes(type: RepositorySnapshot.name, - original_repository: self, - my_module: my_module, - created_by: created_by, - team: my_module.experiment.project.team, - permission_level: Extends::SHARED_INVENTORIES_PERMISSION_LEVELS[:not_shared]) - repository_snapshot.provisioning! - repository_snapshot.reload - RepositorySnapshotProvisioningJob.perform_later(repository_snapshot) - repository_snapshot - end - def assigned_rows(my_module) repository_rows.joins(:my_module_repository_rows).where(my_module_repository_rows: { my_module_id: my_module.id }) end diff --git a/app/models/repository_snapshot.rb b/app/models/repository_snapshot.rb index f29ad80d4..5107451a6 100644 --- a/app/models/repository_snapshot.rb +++ b/app/models/repository_snapshot.rb @@ -26,6 +26,19 @@ class RepositorySnapshot < RepositoryBase .order(:parent_id, updated_at: :desc) } + def self.create_preliminary(repository, my_module, created_by = nil) + created_by ||= repository.created_by + repository_snapshot = repository.dup.becomes(RepositorySnapshot) + repository_snapshot.assign_attributes(type: RepositorySnapshot.name, + original_repository: repository, + my_module: my_module, + created_by: created_by, + team: my_module.experiment.project.team, + permission_level: Extends::SHARED_INVENTORIES_PERMISSION_LEVELS[:not_shared]) + repository_snapshot.provisioning! + repository_snapshot.reload + end + def default_columns_count Constants::REPOSITORY_SNAPSHOT_TABLE_DEFAULT_STATE['length'] end diff --git a/app/permissions/my_module.rb b/app/permissions/my_module.rb index bab364e2f..a83fe4495 100644 --- a/app/permissions/my_module.rb +++ b/app/permissions/my_module.rb @@ -11,6 +11,7 @@ Canaid::Permissions.register_for(MyModule) do .each do |perm| can perm do |_, my_module| my_module.active? && + !my_module.status_changing? && my_module.experiment.active? && my_module.experiment.project.active? end diff --git a/app/views/canvas/full_zoom/_my_module.html.erb b/app/views/canvas/full_zoom/_my_module.html.erb index 6a4b27cfc..0707f6328 100644 --- a/app/views/canvas/full_zoom/_my_module.html.erb +++ b/app/views/canvas/full_zoom/_my_module.html.erb @@ -40,6 +40,10 @@ <% end %>
+ <% if my_module.status_changing %> + + <%= t('experiments.canvas.full_zoom.status_transitioning_label') %> + <% end %> <%= my_module.my_module_status.name %>
diff --git a/app/views/my_modules/status_flow/_task_flow_button.html.erb b/app/views/my_modules/status_flow/_task_flow_button.html.erb index ec72ea7e9..6cd25ddbd 100644 --- a/app/views/my_modules/status_flow/_task_flow_button.html.erb +++ b/app/views/my_modules/status_flow/_task_flow_button.html.erb @@ -1,13 +1,23 @@ <% status = my_module.my_module_status %> -
<%= t('my_module_statuses.dropdown.status_label') %>
- +