mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-13 16:45:18 +08:00
Merge branch 'develop' into kb_SCI-11055_data-e2e-protocol-templates
This commit is contained in:
commit
3433239dde
12 changed files with 106 additions and 23 deletions
|
@ -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
|
||||
|
|
|
@ -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', {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue