diff --git a/app/api/chemotion/attachment_api.rb b/app/api/chemotion/attachment_api.rb index 92bff04b90..9c252c8ccd 100644 --- a/app/api/chemotion/attachment_api.rb +++ b/app/api/chemotion/attachment_api.rb @@ -77,6 +77,8 @@ def remove_duplicated(att) resource :attachments do before do + next if request.path.end_with?('bulk_delete') && request.request_method == 'DELETE' + @attachment = Attachment.find_by(id: params[:attachment_id]) @attachment = Attachment.find_by(identifier: params[:identifier]) if @attachment.nil? && params[:identifier] @@ -112,6 +114,25 @@ def remove_duplicated(att) end end + desc 'Bulk Delete Attachments' + delete 'bulk_delete' do + ids = params[:ids] + attachments = Attachment.where(id: ids) + + unpermitted_attachments = attachments.reject { |attachment| writable?(attachment) } + + if unpermitted_attachments.any? + error!('401 Unauthorized', 401) + else + deleted_attachments = attachments.destroy_all + end + + render json: { deleted_attachments: deleted_attachments }, status: :ok + rescue StandardError => e + render json: { error: e.message }, status: :unprocessable_entity + Rails.logger.error("Error deleting attachments: #{e.message}") + end + desc 'Delete Attachment' delete ':attachment_id' do present Usecases::Attachments::Delete.execute!(@attachment), diff --git a/app/packs/src/apps/mydb/inbox/DeviceBox.js b/app/packs/src/apps/mydb/inbox/DeviceBox.js index 6628e5398d..cc947400bb 100644 --- a/app/packs/src/apps/mydb/inbox/DeviceBox.js +++ b/app/packs/src/apps/mydb/inbox/DeviceBox.js @@ -188,6 +188,8 @@ export default class DeviceBox extends React.Component { const currentItemsCount = device_box.children.length; const itemsDeleted = checkedDeviceIds.length; + const attachmentIdsToDelete = []; + checkedDeviceIds.forEach((checkedDeviceId) => { const datasetToDelete = device_box.children.find((dataset) => dataset.id === checkedDeviceId); if (datasetToDelete) { @@ -199,11 +201,15 @@ export default class DeviceBox extends React.Component { device_box.children.forEach((dataset) => { const attachmentToDelete = dataset.attachments.find((attachment) => attachment.id === checkedId); if (attachmentToDelete) { - InboxActions.deleteAttachment(attachmentToDelete, false); + attachmentIdsToDelete.push(checkedId); } }); }); + if (attachmentIdsToDelete.length > 0) { + InboxActions.bulkDeleteAttachments(attachmentIdsToDelete, false); + } + const params = { checkedDeviceIds: [], checkedIds: [], @@ -378,4 +384,4 @@ DeviceBox.propTypes = { DeviceBox.defaultProps = { largerInbox: false, deviceBoxVisible: false, -}; \ No newline at end of file +}; diff --git a/app/packs/src/fetchers/AttachmentFetcher.js b/app/packs/src/fetchers/AttachmentFetcher.js index 2858fb0028..b3731b4c4a 100644 --- a/app/packs/src/fetchers/AttachmentFetcher.js +++ b/app/packs/src/fetchers/AttachmentFetcher.js @@ -343,6 +343,25 @@ export default class AttachmentFetcher { return promise; } + static bulkDeleteAttachments(attachmentIdsToDelete) { + const promise = fetch('/api/v1/attachments/bulk_delete', { + credentials: 'same-origin', + method: 'DELETE', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ ids: attachmentIdsToDelete }), + }) + .then((response) => response.json()) + .then((json) => new Attachment(json.attachment)) + .catch((errorMessage) => { + console.log(errorMessage); + }); + + return promise; + } + static deleteContainerLink(params) { const promise = fetch(`/api/v1/attachments/link/${params.id}`, { credentials: 'same-origin', @@ -523,7 +542,7 @@ export default class AttachmentFetcher { let jcampIds = oldSpcInfos.map((spc) => (spc.idx)); const fetchedFilesIdxs = json.files.map((file) => (file.id)); jcampIds = [...jcampIds, ...fetchedFilesIdxs]; - + return AttachmentFetcher.combineSpectra(jcampIds, curveIdx).then((res) => { return json; }).catch((errMsg) => { diff --git a/app/packs/src/stores/alt/actions/InboxActions.js b/app/packs/src/stores/alt/actions/InboxActions.js index e8d15b7b78..14e143145f 100644 --- a/app/packs/src/stores/alt/actions/InboxActions.js +++ b/app/packs/src/stores/alt/actions/InboxActions.js @@ -151,6 +151,20 @@ class InboxActions { }; } + bulkDeleteAttachments(attachmentIdsToDelete, fromUnsorted = false) { + return (dispatch) => { + AttachmentFetcher.bulkDeleteAttachments(attachmentIdsToDelete) + .then((result) => { + dispatch({ + result, + fromUnsorted, + }); + }).catch((errorMessage) => { + console.log(errorMessage); + }); + }; + } + deleteContainerLink(params) { return (dispatch) => { AttachmentFetcher.deleteContainerLink(params) diff --git a/app/packs/src/stores/alt/stores/InboxStore.js b/app/packs/src/stores/alt/stores/InboxStore.js index 46c4ed4f9a..47dcd113a6 100644 --- a/app/packs/src/stores/alt/stores/InboxStore.js +++ b/app/packs/src/stores/alt/stores/InboxStore.js @@ -41,6 +41,7 @@ class InboxStore { handleRemoveUnlinkedAttachmentFromList: InboxActions.removeUnlinkedAttachmentFromList, handleRemoveDatasetFromList: InboxActions.removeDatasetFromList, handleDeleteAttachment: InboxActions.deleteAttachment, + handleBulkDeleteAttachment: InboxActions.bulkDeleteAttachments, handleDeleteContainer: InboxActions.deleteContainer, handleBackToInbox: InboxActions.backToInbox, handleDeleteContainerLink: InboxActions.deleteContainerLink, @@ -242,6 +243,28 @@ class InboxStore { } } + handleBulkDeleteAttachment(payload) { + if (payload?.fromUnsorted) { + const { inbox } = this.state; + + const updatedAttachments = inbox.unlinked_attachments.filter( + (attachment) => attachment.id !== payload?.result.id + ); + + this.setState({ + inbox: { + ...inbox, + unlinked_attachments: updatedAttachments, + }, + }); + this.countAttachments(); + } else { + const { activeDeviceBoxId, currentContainerPage } = this.state; + + InboxActions.fetchInboxContainer(activeDeviceBoxId, currentContainerPage); + } + } + handleDeleteContainerLink(result) { const { currentPage, itemsPerPage } = this.state; InboxActions.fetchInbox({ currentPage, itemsPerPage }); @@ -257,7 +280,17 @@ class InboxStore { newInbox.children.splice(parentIndex, 1); this.setState({ inbox: newInbox }); } else { - InboxActions.fetchInboxContainer(activeDeviceBoxId, currentContainerPage); + const updatedChildren = inbox.children.map((parent) => { + if (parent.children && parent.children.length > 0) { + const newParent = { ...parent }; + newParent.children = parent.children.filter((child) => child.id !== result.id); + return newParent; + } + return parent; + }); + + const updatedInbox = { ...inbox, children: updatedChildren }; + this.setState({ inbox: updatedInbox }); } }