mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-03-04 19:53:19 +08:00
Add endpoint for assigning multiple task to inventory [SCI-10429]
This commit is contained in:
parent
11c78d3074
commit
abbd37b9c0
6 changed files with 163 additions and 29 deletions
|
@ -3,12 +3,13 @@
|
|||
class MyModuleRepositoriesController < ApplicationController
|
||||
include ApplicationHelper
|
||||
|
||||
before_action :load_my_module
|
||||
before_action :load_my_module, except: :assign_my_modules
|
||||
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_my_module_view_permissions, except: %i(update consume_modal update_consumption assign_my_modules)
|
||||
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: %i(update create)
|
||||
before_action :load_my_modules, only: :assign_my_modules
|
||||
|
||||
def index_dt
|
||||
@draw = params[:draw].to_i
|
||||
|
@ -41,6 +42,31 @@ class MyModuleRepositoriesController < ApplicationController
|
|||
render rows_view
|
||||
end
|
||||
|
||||
def assign_my_modules
|
||||
assigned_count = 0
|
||||
skipped_count = 0
|
||||
status = :ok
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
@my_modules.find_each do |my_module|
|
||||
service = RepositoryRows::MyModuleAssignUnassignService.call(
|
||||
my_module:,
|
||||
repository: @repository,
|
||||
user: current_user,
|
||||
params:
|
||||
)
|
||||
unless service.succeed?
|
||||
status = :unprocessable_entity
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
assigned_count += service.assigned_rows_count
|
||||
skipped_count += (params[:rows_to_assign].length - service.assigned_rows_count)
|
||||
end
|
||||
end
|
||||
|
||||
render json: { assigned_count:, skipped_count: }, status:
|
||||
end
|
||||
|
||||
def create
|
||||
repository_row = RepositoryRow.find(params[:repository_row_id])
|
||||
repository = repository_row.repository
|
||||
|
@ -215,6 +241,12 @@ class MyModuleRepositoriesController < ApplicationController
|
|||
render_404 unless @repository
|
||||
end
|
||||
|
||||
def load_my_modules
|
||||
@my_modules = MyModule.where(id: params[:my_module_ids])
|
||||
|
||||
render_403 unless @my_modules.all? { |my_module| can_assign_my_module_repository_rows?(my_module) }
|
||||
end
|
||||
|
||||
def check_my_module_view_permissions
|
||||
render_403 unless can_read_my_module?(@my_module)
|
||||
end
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
</label>
|
||||
|
||||
<SelectDropdown
|
||||
:value="selectedTask"
|
||||
:value="selectedTasks"
|
||||
:disabled="!selectedExperiment"
|
||||
:searchable="true"
|
||||
ref="tasksSelector"
|
||||
|
@ -102,6 +102,8 @@
|
|||
:options="tasks"
|
||||
:isLoading="tasksLoading"
|
||||
:placeholder="tasksSelectorPlaceholder"
|
||||
:multiple="true"
|
||||
:withCheckboxes="true"
|
||||
:no-options-placeholder="
|
||||
i18n.t(
|
||||
'repositories.modal_assign_items_to_task.body.task_select.no_options_placeholder'
|
||||
|
@ -115,7 +117,7 @@
|
|||
type="button"
|
||||
class="btn btn-primary"
|
||||
data-dismiss="modal"
|
||||
:disabled="!selectedTask"
|
||||
:disabled="!selectedTasks.length"
|
||||
@click="assign"
|
||||
>
|
||||
{{ i18n.t("repositories.modal_assign_items_to_task.assign.text") }}
|
||||
|
@ -127,6 +129,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
/* global HelperModule */
|
||||
import SelectDropdown from "../shared/select_dropdown.vue";
|
||||
|
||||
export default {
|
||||
|
@ -143,7 +146,7 @@ export default {
|
|||
tasks: [],
|
||||
selectedProject: null,
|
||||
selectedExperiment: null,
|
||||
selectedTask: null,
|
||||
selectedTasks: [],
|
||||
projectsLoading: null,
|
||||
experimentsLoading: null,
|
||||
tasksLoading: null
|
||||
|
@ -206,9 +209,6 @@ export default {
|
|||
taskURL() {
|
||||
return `${this.urls.tasks}?experiment_id=${this.selectedExperiment
|
||||
|| ''}`;
|
||||
},
|
||||
assignURL() {
|
||||
return this.urls.assign.replace(':module_id', this.selectedTask);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -259,7 +259,7 @@ export default {
|
|||
});
|
||||
},
|
||||
changeTask(value) {
|
||||
this.selectedTask = value;
|
||||
this.selectedTasks = value;
|
||||
},
|
||||
resetProjectSelector() {
|
||||
this.projects = [];
|
||||
|
@ -271,7 +271,7 @@ export default {
|
|||
},
|
||||
resetTaskSelector() {
|
||||
this.tasks = [];
|
||||
this.selectedTask = null;
|
||||
this.selectedTasks = [];
|
||||
},
|
||||
resetSelectors() {
|
||||
this.resetTaskSelector();
|
||||
|
@ -279,20 +279,33 @@ export default {
|
|||
this.resetProjectSelector();
|
||||
},
|
||||
assign() {
|
||||
if (!this.selectedTask) return;
|
||||
if (!this.selectedTasks.length) return;
|
||||
|
||||
$.ajax({
|
||||
url: this.assignURL,
|
||||
type: 'PATCH',
|
||||
url: this.urls.assign,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: { rows_to_assign: this.rowsToAssign }
|
||||
}).done(({ assigned_count }) => {
|
||||
const skipped_count = this.rowsToAssign.length - assigned_count;
|
||||
|
||||
if (skipped_count) {
|
||||
HelperModule.flashAlertMsg(this.i18n.t('repositories.modal_assign_items_to_task.assign.flash_some_assignments_success', { assigned_count, skipped_count }), 'success');
|
||||
data: {
|
||||
rows_to_assign: this.rowsToAssign,
|
||||
my_module_ids: this.selectedTasks
|
||||
}
|
||||
}).done(({ assigned_count: assignedCount, skipped_count: skippedCount }) => {
|
||||
if (skippedCount) {
|
||||
HelperModule.flashAlertMsg(
|
||||
this.i18n.t(
|
||||
'repositories.modal_assign_items_to_task.assign.flash_some_assignments_success',
|
||||
{ assigned_count: assignedCount, skipped_count: skippedCount }
|
||||
),
|
||||
'success'
|
||||
);
|
||||
} else {
|
||||
HelperModule.flashAlertMsg(this.i18n.t('repositories.modal_assign_items_to_task.assign.flash_all_assignments_success', { count: assigned_count }), 'success');
|
||||
HelperModule.flashAlertMsg(
|
||||
this.i18n.t(
|
||||
'repositories.modal_assign_items_to_task.assign.flash_all_assignments_success',
|
||||
{ count: assignedCount }
|
||||
),
|
||||
'success'
|
||||
);
|
||||
}
|
||||
}).fail(() => {
|
||||
HelperModule.flashAlertMsg(this.i18n.t('repositories.modal_assign_items_to_task.assign.flash_assignments_failure'), 'danger');
|
||||
|
@ -309,7 +322,7 @@ export default {
|
|||
.dataTable()
|
||||
.api()
|
||||
.ajax
|
||||
.reload();
|
||||
.reload(null, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div
|
||||
class="assign-items-to-task-modal-container"
|
||||
data-assign-url="<%= my_module_repository_path(":module_id") %>"
|
||||
data-assign-url="<%= assign_my_modules_url(id: @repository.id) %>"
|
||||
data-projects-url="<%= inventory_assigning_project_filter_projects_path %>"
|
||||
data-experiments-url="<%= inventory_assigning_experiment_filter_experiments_path %>"
|
||||
data-tasks-url="<%= inventory_assigning_my_module_filter_my_modules_path %>"
|
||||
|
|
|
@ -2226,26 +2226,26 @@ en:
|
|||
modal_assign_items_to_task:
|
||||
title: "Assign to task"
|
||||
body:
|
||||
description: "Type in the fields below to find the right task."
|
||||
description: "Select the fields below to assign item to task(s)."
|
||||
project_select:
|
||||
label: "Project"
|
||||
placeholder: "Enter project name"
|
||||
placeholder: "Select or enter Project name"
|
||||
no_options_placeholder: "No projects available to select"
|
||||
experiment_select:
|
||||
label: "Experiment"
|
||||
placeholder: "Enter Experiment name"
|
||||
placeholder: "Select or enter Experiment name"
|
||||
disabled_placeholder: "Select Project to enable Experiment"
|
||||
no_options_placeholder: "No experiments available to select"
|
||||
task_select:
|
||||
label: "Task"
|
||||
placeholder: "Enter Task name"
|
||||
disabled_placeholder: "Select Experiment to enable Task"
|
||||
disabled_placeholder: "Select or enter Task name"
|
||||
no_options_placeholder: "No tasks available to assign items"
|
||||
assign:
|
||||
text: "Assign to task"
|
||||
flash_all_assignments_success: "Successfully assigned %{count} item(s) to the task."
|
||||
flash_some_assignments_success: "Successfully assigned %{assigned_count} item(s) to the task. %{skipped_count} item(s) were already assigned to the task."
|
||||
flash_assignments_failure: "Failed to assign item(s) to task."
|
||||
flash_all_assignments_success: "Successfully assigned %{count} item(s) to the task(s)."
|
||||
flash_some_assignments_success: "Successfully assigned %{assigned_count} item(s) to the task(s). %{skipped_count} item(s) were already assigned to the task(s)."
|
||||
flash_assignments_failure: "Failed to assign item(s) to task(s)."
|
||||
modal_delete_record:
|
||||
title: "Delete items"
|
||||
notice: "Are you sure you want to delete the selected item(s)?"
|
||||
|
|
|
@ -553,6 +553,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
end
|
||||
post 'repository/:id/assign_my_modules', to: 'my_module_repositories#assign_my_modules', as: :assign_my_modules
|
||||
|
||||
resources :steps, only: %i(index update destroy show) do
|
||||
resources :step_orderable_elements do
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe RepositoryRows::MyModuleAssignUnassignService do
|
||||
let(:user) { create :user }
|
||||
let(:team) { create :team, created_by: user }
|
||||
let(:project) { create(:project, team:, created_by: user) }
|
||||
let(:experiment) { create(:experiment, :with_tasks, project:) }
|
||||
let(:my_module) { create(:my_module, experiment:) }
|
||||
|
||||
let(:repository) { create :repository, team:, created_by: user }
|
||||
let(:rows) do
|
||||
create_list(:repository_row, 10, repository:) do |row, i|
|
||||
row.name = "My Row (#{i + 1})"
|
||||
end
|
||||
end
|
||||
let(:service_call) { described_class.call(**valid_attributes) }
|
||||
let(:valid_attributes) do
|
||||
{
|
||||
my_module:,
|
||||
repository:,
|
||||
user:,
|
||||
params:
|
||||
}
|
||||
end
|
||||
let(:rows_to_assign) { rows.take(6).pluck(:id) }
|
||||
let(:rows_to_unassign) { repository.repository_rows.where.not(id: rows_to_assign).order(:id).pluck(:id) }
|
||||
|
||||
context 'single module' do
|
||||
context 'assigning items' do
|
||||
let(:rows_to_assign) { rows.take(6).pluck(:id) }
|
||||
let(:rows_to_unassign) { repository.repository_rows.where.not(id: rows_to_assign).order(:id).pluck(:id) }
|
||||
let(:params) do
|
||||
{
|
||||
rows_to_assign:,
|
||||
rows_to_unassign:,
|
||||
downstream: false
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates a new assignment' do
|
||||
expect { service_call }.to change { MyModuleRepositoryRow.count }.by rows_to_assign.count
|
||||
end
|
||||
|
||||
it 'unassigns and assigns items' do
|
||||
rows_to_unassign.each do |row_id|
|
||||
my_module.my_module_repository_rows.create!(repository_row_id: row_id, assigned_by: user)
|
||||
end
|
||||
|
||||
service_call
|
||||
expect(
|
||||
my_module.my_module_repository_rows.order(:repository_row_id).pluck(:repository_row_id)
|
||||
).to eq rows_to_assign
|
||||
end
|
||||
|
||||
it 'does nothing' do
|
||||
rows_to_assign.each do |row_id|
|
||||
my_module.my_module_repository_rows.create!(repository_row_id: row_id, assigned_by: user)
|
||||
end
|
||||
|
||||
expect { service_call }.to change { MyModuleRepositoryRow.count }.by 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'unassigning' do
|
||||
let(:params) do
|
||||
{
|
||||
rows_to_assign: [],
|
||||
rows_to_unassign: rows.pluck(:id),
|
||||
downstream: false
|
||||
}
|
||||
end
|
||||
let(:rows_to_assign) { [] }
|
||||
let(:rows_to_unassign) { rows.pluck(:id) }
|
||||
it 'unassigns items' do
|
||||
rows_to_unassign.each do |row_id|
|
||||
my_module.my_module_repository_rows.create!(repository_row_id: row_id, assigned_by: user)
|
||||
end
|
||||
initial_count = my_module.my_module_repository_rows.count
|
||||
|
||||
service_call
|
||||
expect(my_module.my_module_repository_rows.count).to eq 0
|
||||
expect(my_module.my_module_repository_rows.count).to_not eq initial_count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue