Merge branch 'develop' into kb_SCI-11055_data-e2e-protocol-templates

This commit is contained in:
Klemen Benedicic 2024-10-10 13:35:18 +02:00
commit 3433239dde
12 changed files with 106 additions and 23 deletions

View file

@ -54,6 +54,9 @@ class StorageLocationRepositoryRowsController < ApplicationController
def move
ActiveRecord::Base.transaction do
@original_storage_location = @storage_location_repository_row.storage_location
@original_position = @storage_location_repository_row.human_readable_position
@storage_location_repository_row.discard
@storage_location_repository_row = StorageLocationRepositoryRow.create!(
repository_row: @repository_row,
@ -61,7 +64,13 @@ class StorageLocationRepositoryRowsController < ApplicationController
metadata: storage_location_repository_row_params[:metadata] || {},
created_by: current_user
)
log_activity(:storage_location_repository_row_moved)
log_activity(
:storage_location_repository_row_moved,
{
storage_location_original: @original_storage_location.id,
position_original: @original_position
}
)
render json: @storage_location_repository_row,
serializer: Lists::StorageLocationRepositoryRowSerializer
rescue ActiveRecord::RecordInvalid => e

View file

@ -86,7 +86,7 @@ class StorageLocationsController < ApplicationController
def duplicate
ActiveRecord::Base.transaction do
new_storage_location = @storage_location.duplicate!(current_user)
new_storage_location = @storage_location.duplicate!(current_user, current_team)
if new_storage_location
@storage_location = new_storage_location
log_activity('storage_location_created')
@ -104,9 +104,11 @@ class StorageLocationsController < ApplicationController
if move_params[:destination_storage_location_id] == 'root_storage_location'
nil
else
current_team.storage_locations.find(move_params[:destination_storage_location_id])
StorageLocation.find(move_params[:destination_storage_location_id])
end
render_403 and return unless can_manage_storage_location?(destination_storage_location)
@storage_location.update!(parent: destination_storage_location)
log_activity('storage_location_moved', {

View file

@ -54,8 +54,27 @@
v-if="shareRepository"
:object="shareRepository"
:globalShareEnabled="true"
:confirmationModal="$refs.shareConfirmationModal"
@close="shareRepository = null"
@share="updateTable" />
<ConfirmationModal
ref="shareConfirmationModal"
:title="i18n.t('repositories.index.modal_confirm_sharing.title')"
:description="`
<p>${i18n.t('repositories.index.modal_confirm_sharing.description_1')}</p>
<p><b>${i18n.t('repositories.index.modal_confirm_sharing.description_2')}</b></p>
`"
:confirmClass="'btn btn-danger'"
:confirmText="i18n.t('repositories.index.modal_confirm_sharing.confirm')"
:e2eAttributes="{
modalName: 'e2e-MD-confirmSharingChanges',
title: 'e2e-TX-confirmSharingChangesModal-title',
content: 'e2e-TX-confirmSharingChangesModal-content',
close: 'e2e-BT-confirmSharingChangesModal-close',
cancel: 'e2e-BT-confirmSharingChangesModal-cancel',
confirm: 'e2e-BT-confirmSharingChangesModal-delete'
}"
></ConfirmationModal>
</template>
<script>

View file

@ -77,27 +77,52 @@ export default {
name: 'ShareObjectModal',
props: {
object: Object,
globalShareEnabled: { type: Boolean, default: false }
globalShareEnabled: { type: Boolean, default: false },
confirmationModal: { type: Object }
},
mixins: [modalMixin],
data() {
return {
sharedWithAllRead: this.object.shared_read || this.object.shared_write,
sharedWithAllWrite: this.object.shared_write,
shareableTeams: [],
permission_changes: {}
initialState: {},
shareableTeams: []
};
},
mounted() {
this.getTeams();
this.initTeams();
},
computed: {
willUnshare() {
if (this.globalShareEnabled && !this.sharedWithAllRead && this.initialState.sharedWithAllRead) return true;
// true if any team would switch from shared to unshared, based on initial state
return this.shareableTeams.some((t) => {
return this.initialState.shareableTeams.find((it) => t.id === it.id).attributes.private_shared_with && !t.attributes.private_shared_with;
});
}
},
methods: {
getTeams() {
initTeams() {
axios.get(this.object.urls.shareable_teams).then((response) => {
this.initialState = {
shareableTeams: JSON.parse(JSON.stringify(response.data.data)), // object needs to be deep cloned to get rid of references
sharedWithAllRead: this.sharedWithAllRead,
sharedWithAllWrite: this.sharedWithAllWrite
};
this.shareableTeams = response.data.data;
});
},
submit() {
async submit() {
$(this.$refs.modal).hide();
if (this.confirmationModal ? !this.willUnshare || await this.confirmationModal.show() : true) {
this.doRequest();
} else {
$(this.$refs.modal).show();
}
},
doRequest() {
const data = {
select_all_teams: this.sharedWithAllRead,
select_all_write_permission: this.sharedWithAllWrite,

View file

@ -34,6 +34,7 @@
:selectedContainer="assignToContainer"
:selectedPosition="assignToPosition"
:selectedRow="rowIdToMove"
:selectedRowName="rowNameToMove"
:cellId="cellIdToUnassign"
@close="openAssignModal = false; resetTableSearch(); this.reloadingTable = true"
></AssignModal>
@ -115,6 +116,7 @@ export default {
assignToPosition: null,
assignToContainer: null,
rowIdToMove: null,
rowNameToMove: null,
cellIdToUnassign: null,
assignMode: 'assign',
storageLocationUnassignDescription: ''
@ -219,6 +221,7 @@ export default {
assignRow() {
this.openAssignModal = true;
this.rowIdToMove = null;
this.rowNameToMove = null;
this.assignToContainer = this.containerId;
this.assignToPosition = null;
this.cellIdToUnassign = null;
@ -227,6 +230,7 @@ export default {
assignRowToPosition(position) {
this.openAssignModal = true;
this.rowIdToMove = null;
this.rowNameToMove = null;
this.assignToContainer = this.containerId;
this.assignToPosition = position;
this.cellIdToUnassign = null;
@ -235,6 +239,7 @@ export default {
moveRow(_event, data) {
this.openAssignModal = true;
this.rowIdToMove = data[0].row_id;
this.rowNameToMove = data[0].row_name || this.i18n.t('storage_locations.show.hidden');
this.assignToContainer = null;
this.assignToPosition = null;
this.cellIdToUnassign = data[0].id;

View file

@ -10,31 +10,37 @@
<h4 v-if="selectedPosition" class="modal-title truncate !block">
{{ i18n.t(`storage_locations.show.assign_modal.selected_position_title`, { position: formattedPosition }) }}
</h4>
<h4 v-else-if="selectedRow && selectedRowName" class="modal-title truncate !block">
<h4 v-else-if="assignMode === 'assign' && selectedRow && selectedRowName" class="modal-title truncate !block">
{{ i18n.t(`storage_locations.show.assign_modal.selected_row_title`) }}
</h4>
<h4 v-else-if="assignMode === 'move'" class="modal-title truncate !block">
{{ i18n.t(`storage_locations.show.assign_modal.move_title`, { name: selectedRowName }) }}
</h4>
<h4 v-else class="modal-title truncate !block">
{{ i18n.t(`storage_locations.show.assign_modal.${assignMode}_title`) }}
{{ i18n.t(`storage_locations.show.assign_modal.assign_title`) }}
</h4>
</div>
<div class="modal-body">
<p v-if="selectedRow && selectedRowName" class="mb-4">
{{ i18n.t(`storage_locations.show.assign_modal.selected_row_description`, { name: selectedRowName }) }}
</p>
<h4 v-else-if="assignMode === 'move'" class="modal-title truncate !block">
{{ i18n.t(`storage_locations.show.assign_modal.move_description`, { name: selectedRowName }) }}
</h4>
<p v-else class="mb-4">
{{ i18n.t(`storage_locations.show.assign_modal.${assignMode}_description`) }}
{{ i18n.t(`storage_locations.show.assign_modal.assign_description`) }}
</p>
<RowSelector v-if="!selectedRow" @change="this.rowId = $event" class="mb-4"></RowSelector>
<ContainerSelector v-if="!selectedContainer" @change="this.containerId = $event"></ContainerSelector>
<PositionSelector
v-if="containerId && !selectedPosition"
v-if="containerId && containerId > 0 && !selectedPosition"
:key="containerId"
:selectedContainerId="containerId"
@change="this.position = $event"></PositionSelector>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ i18n.t('general.cancel') }}</button>
<button class="btn btn-primary" type="submit">
<button class="btn btn-primary" type="submit" :disabled="!validObject">
{{ i18n.t(`storage_locations.show.assign_modal.${assignMode}_action`) }}
</button>
</div>
@ -70,6 +76,9 @@ export default {
},
mixins: [modalMixin],
computed: {
validObject() {
return this.rowId && this.containerId && this.containerId > 0 && this.position;
},
createUrl() {
return storage_location_storage_location_repository_rows_path({
storage_location_id: this.containerId

View file

@ -43,7 +43,7 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ i18n.t('general.cancel') }}</button>
<button class="btn btn-primary" type="submit">
<button class="btn btn-primary" :disabled="!validContainer" type="submit">
{{ i18n.t('general.move') }}
</button>
</div>
@ -69,6 +69,11 @@ export default {
created() {
this.teamId = this.selectedObject.team_id;
},
computed: {
validContainer() {
return (this.selectedStorageLocationId && this.selectedStorageLocationId > 0) || this.selectedStorageLocationId === null;
}
},
mixins: [modalMixin, MoveTreeMixin],
data() {
return {

View file

@ -61,14 +61,15 @@ class StorageLocation < ApplicationRecord
storage_location_repository_rows.count.zero?
end
def duplicate!(user)
def duplicate!(user, team)
ActiveRecord::Base.transaction do
new_storage_location = dup
new_storage_location.name = next_clone_name
new_storage_location.team = team unless parent_id
new_storage_location.created_by = user
new_storage_location.save!
copy_image(self, new_storage_location)
recursive_duplicate(id, new_storage_location.id, user)
recursive_duplicate(id, new_storage_location.id, user, new_storage_location.team)
new_storage_location
rescue ActiveRecord::RecordInvalid
false
@ -144,14 +145,15 @@ class StorageLocation < ApplicationRecord
private
def recursive_duplicate(old_parent_id = nil, new_parent_id = nil, user = nil)
def recursive_duplicate(old_parent_id = nil, new_parent_id = nil, user = nil, team = 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.team = team
new_child.created_by = user
new_child.save!
copy_image(child, new_child)
recursive_duplicate(child.id, new_child.id, user)
recursive_duplicate(child.id, new_child.id, user, team)
end
end

View file

@ -83,7 +83,7 @@ class RepositoryDatatableService
repository_rows =
if @repository.archived? || @repository.is_a?(RepositorySnapshot)
# don't load reminders for archived repositories or snapshots
repository_rows.select('FALSE AS has_active_stock_reminders, FALSE AS has_active_datetime_reminders')
repository_rows.select('FALSE AS has_active_reminders')
else
repository_rows.left_outer_joins_active_reminders(@repository, @user)
.select('COUNT(repository_cells_with_active_reminders.id) > 0 AS has_active_reminders')

View file

@ -20,6 +20,8 @@ class RepositorySnapshotDatatableService < RepositoryDatatableService
repository_rows = fetch_rows(search_value).preload(Extends::REPOSITORY_ROWS_PRELOAD_RELATIONS)
repository_rows = repository_rows.preload(:repository_columns, repository_cells: { value: @repository.cell_preload_includes }) if @preload_cells
repository_rows = repository_rows.preload(:repository_stock_cell, :repository_stock_value) if @repository.has_stock_management?
# don't load reminders for snapshots
repository_rows = repository_rows.select('FALSE AS has_active_reminders') if Repository.reminders_enabled?
sort_rows(order_by_column, repository_rows)
end

View file

@ -2014,6 +2014,11 @@ en:
name_placeholder: "My inventory"
submit: "Create"
success_flash_html: "Inventory <strong>%{name}</strong> successfully created."
modal_confirm_sharing:
title: "Inventory sharing changes"
description_1: "You will no longer share this inventory with some of the teams. All unshared inventory items assigned to tasks will be automatically removed and this action is irreversible. Any item relationship links (if they exist) will also be deleted."
description_2: "Are you sure you want to apply the changes you made?"
confirm: "Apply"
export:
notification:
error:
@ -2696,9 +2701,9 @@ en:
selected_position_title: 'Assign to position %{position}'
selected_row_title: 'Assign new location'
assign_title: 'Assign position'
move_title: 'Move item'
move_title: 'Move %{name}'
assign_description: 'Select an item to assign it to a location.'
move_description: 'Select a new location for your item.'
move_description: 'Select where you want to move %{name}.'
selected_row_description: "Select a location for the item %{name}."
assign_action: 'Assign'
move_action: 'Move'

View file

@ -338,7 +338,7 @@ en:
container_storage_location_sharing_updated_html: "%{user} changed permission of shared box %{storage_location} with team %{team} to %{permission_level}."
storage_location_repository_row_created_html: "%{user} assigned %{repository_row} to box %{storage_location} %{position}."
storage_location_repository_row_deleted_html: "%{user} unassigned %{repository_row} from box %{storage_location} %{position}."
storage_location_repository_row_moved_html: "%{user} moved item %{repository_row} from box %{storage_location_original} %{positions} to box %{storage_location_destination} %{positions}."
storage_location_repository_row_moved_html: "%{user} moved item %{repository_row} from box %{storage_location_original} %{position_original} to box %{storage_location} %{position}."
container_storage_location_imported_html: "%{user} assigned %{assigned_count} item(s) and unassigned %{unassigned_count} item(s) by import to %{storage_location}."
activity_name:
create_project: "Project created"