Add duplicate action to locations [SCI-10862]

This commit is contained in:
Anton 2024-07-22 12:12:47 +02:00
parent e56e9b7dac
commit 1c3cc71174
7 changed files with 80 additions and 10 deletions

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class StorageLocationsController < ApplicationController
before_action :load_storage_location, only: %i(update destroy)
before_action :load_storage_location, only: %i(update destroy duplicate)
before_action :check_read_permissions, only: :index
before_action :check_manage_permissions, except: :index
before_action :set_breadcrumbs_items, only: :index
@ -51,6 +51,15 @@ class StorageLocationsController < ApplicationController
end
end
def duplicate
new_storage_location = @storage_location.duplicate!
if new_storage_location
render json: new_storage_location, serializer: Lists::StorageLocationSerializer
else
render json: { errors: :failed }, status: :unprocessable_entity
end
end
def actions_toolbar
render json: {
actions:

View file

@ -9,6 +9,7 @@
@create_location="openCreateLocationModal"
@create_box="openCreateBoxModal"
@edit="edit"
@duplicate="duplicate"
@tableReloaded="reloadingTable = false"
/>
<Teleport to="body">
@ -25,8 +26,9 @@
</template>
<script>
/* global */
/* global HelperModule */
import axios from '../../packs/custom_axios.js';
import DataTable from '../shared/datatable/table.vue';
import EditModal from './modals/new_edit.vue';
@ -154,6 +156,16 @@ export default {
this.editModalMode = params[0].container ? 'box' : 'location';
[this.editStorageLocation] = params;
},
duplicate(action) {
axios.post(action.path)
.then(() => {
this.reloadingTable = true;
HelperModule.flashAlertMsg(this.i18n.t('storage_locations.index.duplicate.success_message'), 'success');
})
.catch(() => {
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
});
},
// Renderers
nameRenderer(params) {
const {

View file

@ -7,12 +7,18 @@ module Cloneable
raise NotImplementedError, "Cloneable model must implement the '.parent' method!" unless respond_to?(:parent)
clone_label = I18n.t('general.clone_label')
last_clone_number =
parent.public_send(self.class.table_name)
.select("substring(#{self.class.table_name}.name, '(?:^#{clone_label} )(\\d+)')::int AS clone_number")
.where('name ~ ?', "^#{clone_label} \\d+ - #{Regexp.escape(name)}$")
.order(clone_number: :asc)
.last&.clone_number
records = if parent
parent.public_send(self.class.table_name)
else
self.class.where(parent_id: nil, team: team)
end
last_clone_number = records
.select("substring(#{self.class.table_name}.name, '(?:^#{clone_label} )(\\d+)')::int AS clone_number")
.where('name ~ ?', "^#{clone_label} \\d+ - #{Regexp.escape(name)}$")
.order(clone_number: :asc)
.last&.clone_number
"#{clone_label} #{(last_clone_number || 0) + 1} - #{name}".truncate(Constants::NAME_MAX_LENGTH)
end

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
class StorageLocation < ApplicationRecord
include Cloneable
include Discard::Model
ID_PREFIX = 'SL'
include PrefixedIdModel
@ -14,6 +15,7 @@ class StorageLocation < ApplicationRecord
belongs_to :created_by, class_name: 'User'
has_many :storage_location_repository_rows, inverse_of: :storage_location
has_many :storage_locations, foreign_key: :parent_id, dependent: :destroy, inverse_of: :parent
has_many :repository_rows, through: :storage_location_repository_row
validates :name, length: { maximum: Constants::NAME_MAX_LENGTH }
@ -22,4 +24,43 @@ class StorageLocation < ApplicationRecord
StorageLocation.where(parent_id: id).find_each(&:discard)
storage_location_repository_rows.each(&:discard)
end
def duplicate!
ActiveRecord::Base.transaction do
new_storage_location = dup
new_storage_location.name = next_clone_name
new_storage_location.save!
copy_image(self, new_storage_location)
recursive_duplicate(id, new_storage_location.id)
new_storage_location
rescue ActiveRecord::RecordInvalid
false
end
end
private
def recursive_duplicate(old_parent_id = nil, new_parent_id = nil)
StorageLocation.where(parent_id: old_parent_id).find_each do |child|
new_child = child.dup
new_child.parent_id = new_parent_id
new_child.save!
copy_image(child, new_child)
recursive_duplicate(child.id, new_child.id)
end
end
def copy_image(old_storage_location, new_storage_location)
return unless old_storage_location.image.attached?
old_blob = old_storage_location.image.blob
old_blob.open do |tmp_file|
to_blob = ActiveStorage::Blob.create_and_upload!(
io: tmp_file,
filename: old_blob.filename,
metadata: old_blob.metadata
)
new_storage_location.image.attach(to_blob)
end
end
end

View file

@ -64,7 +64,7 @@ module Toolbars
name: 'duplicate',
label: I18n.t('storage_locations.index.toolbar.duplicate'),
icon: 'sn-icon sn-icon-duplicate',
path: copy_storage_location_path(@storage_locations.first),
path: duplicate_storage_location_path(@storage_locations.first),
type: :emit
}
end

View file

@ -2672,6 +2672,8 @@ en:
head_title: "Locations"
new_location: "New location"
new_box: "New box"
duplicate:
success_message: "Location was successfully duplicated."
toolbar:
edit: 'Edit'
move: 'Move'

View file

@ -813,7 +813,7 @@ Rails.application.routes.draw do
end
member do
post :move
post :copy
post :duplicate
end
resources :storage_location_repository_rows, only: %i(index create destroy update)
end