mirror of
				https://github.com/scinote-eln/scinote-web.git
				synced 2025-11-04 21:09:13 +08:00 
			
		
		
		
	Merge pull request #6075 from aignatov-bio/ai-sci-9088-add-attachments-move-ability
Add move ability to attachments [SCI-9088]
This commit is contained in:
		
						commit
						678e40f04d
					
				
					 15 changed files with 122 additions and 9 deletions
				
			
		| 
						 | 
				
			
			@ -65,6 +65,37 @@ class AssetsController < ApplicationController
 | 
			
		|||
                                          formats: :html) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def move_targets
 | 
			
		||||
    if @assoc.is_a?(Step)
 | 
			
		||||
      protocol = @assoc.protocol
 | 
			
		||||
      render json: { targets: protocol.steps.order(:position).where.not(id: @assoc.id).map { |i| [i.id, i.name] } }
 | 
			
		||||
    elsif @assoc.is_a?(Result)
 | 
			
		||||
      my_module = @assoc.my_module
 | 
			
		||||
      render json: { targets: my_module.results.where.not(id: @assoc.id).map { |i| [i.id, i.name] } }
 | 
			
		||||
    else
 | 
			
		||||
      render json: { targets: [] }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def move
 | 
			
		||||
    ActiveRecord::Base.transaction do
 | 
			
		||||
      if @assoc.is_a?(Step)
 | 
			
		||||
        target = @assoc.protocol.steps.find_by(id: params[:target_id])
 | 
			
		||||
        object_to_update = @asset.step_asset
 | 
			
		||||
        object_to_update.update!(step: target)
 | 
			
		||||
        render json: {}
 | 
			
		||||
      elsif @assoc.is_a?(Result)
 | 
			
		||||
        target = @assoc.my_module.results.find_by(id: params[:target_id])
 | 
			
		||||
        object_to_update = @asset.result_asset
 | 
			
		||||
        object_to_update.update!(result: target)
 | 
			
		||||
        render json: {}
 | 
			
		||||
      end
 | 
			
		||||
    rescue ActiveRecord::RecordInvalid
 | 
			
		||||
      render json: object_to_update.errors, status: :unprocessable_entity
 | 
			
		||||
      raise ActiveRecord::Rollback
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def file_url
 | 
			
		||||
    return render_404 unless @asset.file.attached?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -146,6 +146,8 @@
 | 
			
		|||
                  @step:insert="updateStepsPosition"
 | 
			
		||||
                  @step:elements:loaded="stepToReload = null"
 | 
			
		||||
                  @step:move_element="reloadStep"
 | 
			
		||||
                  @step:attachemnts:loaded="stepToReload = null"
 | 
			
		||||
                  @step:move_attachment="reloadStep"
 | 
			
		||||
                  :reorderStepUrl="steps.length > 1 ? urls.reorder_steps_url : null"
 | 
			
		||||
                  :assignableMyModuleId="protocol.attributes.assignable_my_module_id"
 | 
			
		||||
                />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -183,6 +183,7 @@
 | 
			
		|||
                    @attachment:deleted="attachmentDeleted"
 | 
			
		||||
                    @attachment:uploaded="loadAttachments"
 | 
			
		||||
                    @attachments:order="changeAttachmentsOrder"
 | 
			
		||||
                    @attachment:moved="moveAttachment"
 | 
			
		||||
                    @attachments:viewMode="changeAttachmentsViewMode"
 | 
			
		||||
                    @attachment:viewMode="updateAttachmentViewMode"/>
 | 
			
		||||
      </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -290,6 +291,7 @@
 | 
			
		|||
      stepToReload() {
 | 
			
		||||
        if (this.stepToReload == this.step.id) {
 | 
			
		||||
          this.loadElements();
 | 
			
		||||
          this.loadAttachments();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -330,7 +332,7 @@
 | 
			
		|||
 | 
			
		||||
        $.get(this.urls.attachments_url, (result) => {
 | 
			
		||||
          this.attachments = result.data
 | 
			
		||||
 | 
			
		||||
          this.$emit('step:attachments:loaded');
 | 
			
		||||
          if (this.attachments.findIndex((e) => e.attributes.attached === false) >= 0) {
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
              this.loadAttachments()
 | 
			
		||||
| 
						 | 
				
			
			@ -543,6 +545,11 @@
 | 
			
		|||
        this.$emit('stepUpdated')
 | 
			
		||||
        this.$emit('step:move_element', target_id)
 | 
			
		||||
      },
 | 
			
		||||
      moveAttachment(id, target_id) {
 | 
			
		||||
        this.attachments = this.attachments.filter((a) => a.id !== id );
 | 
			
		||||
        this.$emit('stepUpdated')
 | 
			
		||||
        this.$emit('step:move_attachment', target_id)
 | 
			
		||||
      },
 | 
			
		||||
      duplicateStep() {
 | 
			
		||||
        $.post(this.urls.duplicate_step_url, (result) => {
 | 
			
		||||
          this.$emit('step:insert', result.data);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,6 +135,7 @@
 | 
			
		|||
                    @attachments:openFileModal="showFileModal = true"
 | 
			
		||||
                    @attachment:deleted="attachmentDeleted"
 | 
			
		||||
                    @attachment:uploaded="loadAttachments"
 | 
			
		||||
                    @attachment:moved="moveAttachment"
 | 
			
		||||
                    @attachments:order="changeAttachmentsOrder"
 | 
			
		||||
                    @attachments:viewMode="changeAttachmentsViewMode"
 | 
			
		||||
                    @attachment:viewMode="updateAttachmentViewMode"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -190,6 +191,7 @@
 | 
			
		|||
      resultToReload() {
 | 
			
		||||
        if (this.resultToReload == this.result.attributes.id) {
 | 
			
		||||
          this.loadElements();
 | 
			
		||||
          this.loadAttachments();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -297,7 +299,7 @@
 | 
			
		|||
 | 
			
		||||
        $.get(this.urls.attachments_url, (result) => {
 | 
			
		||||
          this.attachments = result.data
 | 
			
		||||
 | 
			
		||||
          this.$emit('result:attachments:loaded');
 | 
			
		||||
          if (this.attachments.findIndex((e) => e.attributes.attached === false) >= 0) {
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
              this.loadAttachments()
 | 
			
		||||
| 
						 | 
				
			
			@ -355,6 +357,11 @@
 | 
			
		|||
        this.$emit('resultUpdated')
 | 
			
		||||
        this.$emit('result:move_element', target_id)
 | 
			
		||||
      },
 | 
			
		||||
      moveAttachment(id, target_id) {
 | 
			
		||||
        this.attachments = this.attachments.filter((a) => a.id !== id );
 | 
			
		||||
        this.$emit('resultUpdated')
 | 
			
		||||
        this.$emit('result:move_attachment', target_id)
 | 
			
		||||
      },
 | 
			
		||||
      updateName(name) {
 | 
			
		||||
        axios.patch(this.urls.update_url, { result: { name: name } }).then((_) => {
 | 
			
		||||
          this.$emit('updated');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,8 @@
 | 
			
		|||
        :resultToReload="resultToReload"
 | 
			
		||||
        @result:elements:loaded="resultToReload = null"
 | 
			
		||||
        @result:move_element="reloadResult"
 | 
			
		||||
        @result:attachments:loaded="resultToReload = null"
 | 
			
		||||
        @result:move_attachment="reloadResult"
 | 
			
		||||
        @duplicated="resetPageAndReload"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,12 +55,14 @@
 | 
			
		|||
          :parentId="parseInt(parent.id)"
 | 
			
		||||
          @attachment:viewMode="updateAttachmentViewMode"
 | 
			
		||||
          @attachment:delete="deleteAttachment(attachment.id)"
 | 
			
		||||
          @attachment:moved="attachmentMoved"
 | 
			
		||||
        />
 | 
			
		||||
      </template>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
  import AttachmentMovedMixin from './attachments/mixins/attachment_moved.js'
 | 
			
		||||
  import listAttachment from './attachments/list.vue'
 | 
			
		||||
  import inlineAttachment from './attachments/inline.vue'
 | 
			
		||||
  import thumbnailAttachment from './attachments/thumbnail.vue'
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +93,7 @@
 | 
			
		|||
        orderOptions: ['new', 'old', 'divider', 'atoz', 'ztoa']
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    mixins: [WopiFileModal],
 | 
			
		||||
    mixins: [WopiFileModal, AttachmentMovedMixin],
 | 
			
		||||
    components: {
 | 
			
		||||
      thumbnailAttachment,
 | 
			
		||||
      inlineAttachment,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,6 +49,13 @@
 | 
			
		|||
          {{ i18n.t('Download') }}
 | 
			
		||||
        </a>
 | 
			
		||||
      </li>
 | 
			
		||||
      <template v-if="attachment.attributes.urls.move_targets">
 | 
			
		||||
        <li>
 | 
			
		||||
          <a @click.prevent.stop="showMoveModal">
 | 
			
		||||
            {{ i18n.t("assets.context_menu.move") }}
 | 
			
		||||
          </a>
 | 
			
		||||
        </li>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-if="attachment.attributes.urls.delete">
 | 
			
		||||
        <li>
 | 
			
		||||
          <a @click.prevent.stop="deleteModal = true">
 | 
			
		||||
| 
						 | 
				
			
			@ -77,15 +84,22 @@
 | 
			
		|||
        @confirm="deleteAttachment"
 | 
			
		||||
        @cancel="deleteModal = false"
 | 
			
		||||
    />
 | 
			
		||||
    <moveAssetModal v-if="movingAttachment"
 | 
			
		||||
                      :parent_type="attachment.attributes.parent_type"
 | 
			
		||||
                      :targets_url="attachment.attributes.urls.move_targets"
 | 
			
		||||
                      @confirm="moveAttachment($event)" @cancel="closeMoveModal"/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import deleteAttachmentModal from './delete_modal.vue'
 | 
			
		||||
  import moveAssetModal from '../modal/move.vue'
 | 
			
		||||
  import MoveMixin from './mixins/move.js'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'contextMenu',
 | 
			
		||||
    components: { deleteAttachmentModal },
 | 
			
		||||
    components: { deleteAttachmentModal, moveAssetModal },
 | 
			
		||||
    mixins: [MoveMixin],
 | 
			
		||||
    props: {
 | 
			
		||||
      attachment: {
 | 
			
		||||
        type: Object,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,7 @@
 | 
			
		|||
        :attachment="attachment"
 | 
			
		||||
        @attachment:viewMode="updateViewMode"
 | 
			
		||||
        @attachment:delete="deleteAttachment"
 | 
			
		||||
        @attachment:moved="attachmentMoved"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <template v-if="attachment.attributes.wopi">
 | 
			
		||||
| 
						 | 
				
			
			@ -71,13 +72,14 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AttachmentMovedMixin from './mixins/attachment_moved.js';
 | 
			
		||||
  import ContextMenuMixin from './mixins/context_menu.js';
 | 
			
		||||
  import ContextMenu from './context_menu.vue';
 | 
			
		||||
  import PdfViewer from '../../pdf_viewer.vue';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'inlineAttachment',
 | 
			
		||||
    mixins: [ContextMenuMixin],
 | 
			
		||||
    mixins: [ContextMenuMixin, AttachmentMovedMixin],
 | 
			
		||||
    components: { ContextMenu, PdfViewer },
 | 
			
		||||
    props: {
 | 
			
		||||
      attachment: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,17 +35,19 @@
 | 
			
		|||
      :attachment="attachment"
 | 
			
		||||
      @attachment:viewMode="updateViewMode"
 | 
			
		||||
      @attachment:delete="deleteAttachment"
 | 
			
		||||
      @attachment:moved="attachmentMoved"
 | 
			
		||||
    />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AttachmentMovedMixin from './mixins/attachment_moved.js';
 | 
			
		||||
  import ContextMenuMixin from './mixins/context_menu.js'
 | 
			
		||||
  import ContextMenu from './context_menu.vue'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'listAttachment',
 | 
			
		||||
    mixins: [ContextMenuMixin],
 | 
			
		||||
    mixins: [ContextMenuMixin, AttachmentMovedMixin],
 | 
			
		||||
    components: { ContextMenu },
 | 
			
		||||
    props: {
 | 
			
		||||
      attachment: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
export default {
 | 
			
		||||
  methods: {
 | 
			
		||||
    attachmentMoved(attachmentId, targetId) {
 | 
			
		||||
      this.$emit('attachment:moved', attachmentId, targetId);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										25
									
								
								app/javascript/vue/shared/content/attachments/mixins/move.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/javascript/vue/shared/content/attachments/mixins/move.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
import axios from '../../../../../packs/custom_axios.js';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      movingAttachment: false
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    showMoveModal(event) {
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
      this.movingAttachment = true;
 | 
			
		||||
    },
 | 
			
		||||
    closeMoveModal() {
 | 
			
		||||
      this.movingAttachment = false;
 | 
			
		||||
    },
 | 
			
		||||
    moveAttachment(targetId) {
 | 
			
		||||
      axios.post(this.attachment.attributes.urls.move, { target_id: targetId })
 | 
			
		||||
        .then(() => {
 | 
			
		||||
          this.movingAttachment = false;
 | 
			
		||||
          this.$emit('attachment:moved', this.attachment.id, targetId);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +80,7 @@
 | 
			
		|||
      :attachment="attachment"
 | 
			
		||||
      @attachment:viewMode="updateViewMode"
 | 
			
		||||
      @attachment:delete="deleteAttachment"
 | 
			
		||||
      @attachment:moved="attachmentMoved"
 | 
			
		||||
    />
 | 
			
		||||
    <deleteAttachmentModal
 | 
			
		||||
      v-if="deleteModal"
 | 
			
		||||
| 
						 | 
				
			
			@ -92,13 +93,14 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AttachmentMovedMixin from './mixins/attachment_moved.js'
 | 
			
		||||
  import ContextMenuMixin from './mixins/context_menu.js'
 | 
			
		||||
  import ContextMenu from './context_menu.vue'
 | 
			
		||||
  import deleteAttachmentModal from './delete_modal.vue'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'thumbnailAttachment',
 | 
			
		||||
    mixins: [ContextMenuMixin],
 | 
			
		||||
    mixins: [ContextMenuMixin, AttachmentMovedMixin],
 | 
			
		||||
    components: { ContextMenu, deleteAttachmentModal },
 | 
			
		||||
    props: {
 | 
			
		||||
      attachment: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ class AssetSerializer < ActiveModel::Serializer
 | 
			
		|||
  attributes :file_name, :view_mode, :icon, :urls, :updated_at_formatted,
 | 
			
		||||
             :file_size, :medium_preview, :large_preview, :asset_type, :wopi,
 | 
			
		||||
             :wopi_context, :pdf_previewable, :file_size_formatted, :asset_order,
 | 
			
		||||
             :updated_at, :metadata, :image_editable, :image_context, :pdf, :attached
 | 
			
		||||
             :updated_at, :metadata, :image_editable, :image_context, :pdf, :attached, :parent_type
 | 
			
		||||
 | 
			
		||||
  def icon
 | 
			
		||||
    file_fa_icon_class(object)
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +29,11 @@ class AssetSerializer < ActiveModel::Serializer
 | 
			
		|||
    I18n.l(object.updated_at, format: :full_date) if object.updated_at
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def parent_type
 | 
			
		||||
    return 'step' if object.step
 | 
			
		||||
    return 'result' if object.result
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def attached
 | 
			
		||||
    object.file.attached?
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +129,9 @@ class AssetSerializer < ActiveModel::Serializer
 | 
			
		|||
        edit_asset: edit_asset_path(object),
 | 
			
		||||
        marvin_js_start_edit: start_editing_marvin_js_asset_path(object),
 | 
			
		||||
        start_edit_image: start_edit_image_path(object),
 | 
			
		||||
        delete: asset_destroy_path(object)
 | 
			
		||||
        delete: asset_destroy_path(object),
 | 
			
		||||
        move_targets: asset_move_tagets_path(object),
 | 
			
		||||
        move: asset_move_path(object)
 | 
			
		||||
      )
 | 
			
		||||
    end
 | 
			
		||||
    urls[:wopi_action] = object.get_action_url(user, 'embedview') if wopi && can_manage_asset?(user, object)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3345,6 +3345,7 @@ en:
 | 
			
		|||
    context_menu:
 | 
			
		||||
      set_view_size: "SET PREVIEW SIZE"
 | 
			
		||||
      delete: "Delete"
 | 
			
		||||
      move: "Move"
 | 
			
		||||
      inline_html: "Large"
 | 
			
		||||
      thumbnail_html: "Medium"
 | 
			
		||||
      list_html: "List"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -826,6 +826,8 @@ Rails.application.routes.draw do
 | 
			
		|||
    get 'files/:id/load_asset', to: 'assets#load_asset', as: 'load_asset'
 | 
			
		||||
    post 'files/:id/update_image', to: 'assets#update_image',
 | 
			
		||||
                                   as: 'update_asset_image'
 | 
			
		||||
    get 'files/:id/move_targets', to: 'assets#move_targets', as: 'asset_move_tagets'
 | 
			
		||||
    post 'files/:id/move', to: 'assets#move', as: 'asset_move'
 | 
			
		||||
    delete 'files/:id/', to: 'assets#destroy', as: 'asset_destroy'
 | 
			
		||||
    post 'files/create_wopi_file',
 | 
			
		||||
         to: 'assets#create_wopi_file',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue