mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-03-04 19:53:19 +08:00
Implement file versions modal [SCI-11039]
This commit is contained in:
parent
157a23d025
commit
444b561060
7 changed files with 118 additions and 8 deletions
|
@ -197,7 +197,7 @@ class AssetsController < ApplicationController
|
|||
return render_403 unless can_read_team?(@asset.team)
|
||||
|
||||
@asset.last_modified_by = current_user
|
||||
@asset.file.attach(io: params.require(:image), filename: orig_file_name)
|
||||
@asset.attach_file_version(io: params.require(:image), filename: orig_file_name, current_user: current_user)
|
||||
@asset.save!
|
||||
create_edit_image_activity(@asset, current_user, :finish_editing)
|
||||
# release previous image space
|
||||
|
@ -242,9 +242,10 @@ class AssetsController < ApplicationController
|
|||
|
||||
# Asset validation
|
||||
asset = Asset.new(created_by: current_user, team: current_team)
|
||||
asset.file.attach(io: StringIO.new,
|
||||
filename: "#{params[:file_name]}.#{params[:file_type]}",
|
||||
content_type: wopi_content_type(params[:file_type]))
|
||||
asset.attach_file_version(io: StringIO.new,
|
||||
filename: "#{params[:file_name]}.#{params[:file_type]}",
|
||||
content_type: wopi_content_type(params[:file_type]),
|
||||
current_user: current_user)
|
||||
|
||||
unless asset.valid?(:wopi_file_creation)
|
||||
render json: {
|
||||
|
@ -397,6 +398,13 @@ class AssetsController < ApplicationController
|
|||
render json: { checksum: @asset.file.blob.checksum }
|
||||
end
|
||||
|
||||
def versions
|
||||
render(
|
||||
json: [@asset.file.blob] +
|
||||
@asset.previous_files.map(&:blob).sort_by { |b| -1 * b.metadata['version'].to_i }
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_vars
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
@duplicate="duplicate"
|
||||
@viewMode="changeViewMode"
|
||||
@move="showMoveModal"
|
||||
@fileVersionsModal="fileVersionsModal = true"
|
||||
@menu-toggle="$emit('menu-toggle', $event)"
|
||||
></MenuDropdown>
|
||||
<Teleport to="body">
|
||||
|
@ -55,6 +56,11 @@
|
|||
:targets_url="attachment.attributes.urls.move_targets"
|
||||
@confirm="moveAttachment($event)" @cancel="closeMoveModal"
|
||||
/>
|
||||
<FileVersionsModal
|
||||
v-if="fileVersionsModal"
|
||||
:url="attachment.attributes.urls.versions"
|
||||
@close="fileVersionsModal = false"
|
||||
/>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -65,6 +71,7 @@ import deleteAttachmentModal from './delete_modal.vue';
|
|||
import MoveAssetModal from '../modal/move.vue';
|
||||
import MoveMixin from './mixins/move.js';
|
||||
import MenuDropdown from '../../menu_dropdown.vue';
|
||||
import FileVersionsModal from '../../file_versions_modal.vue';
|
||||
import axios from '../../../../packs/custom_axios.js';
|
||||
|
||||
export default {
|
||||
|
@ -73,6 +80,7 @@ export default {
|
|||
RenameAttachmentModal,
|
||||
deleteAttachmentModal,
|
||||
MoveAssetModal,
|
||||
FileVersionsModal,
|
||||
MenuDropdown
|
||||
},
|
||||
mixins: [MoveMixin],
|
||||
|
@ -91,7 +99,8 @@ export default {
|
|||
return {
|
||||
viewModeOptions: ['inline', 'thumbnail', 'list'],
|
||||
deleteModal: false,
|
||||
renameModal: false
|
||||
renameModal: false,
|
||||
fileVersionsModal: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -136,6 +145,12 @@ export default {
|
|||
});
|
||||
});
|
||||
}
|
||||
if (this.attachment.attributes.urls.versions) {
|
||||
menu.push({
|
||||
text: this.i18n.t('assets.context_menu.versions'),
|
||||
emit: 'fileVersionsModal'
|
||||
});
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
},
|
||||
|
|
66
app/javascript/vue/shared/file_versions_modal.vue
Normal file
66
app/javascript/vue/shared/file_versions_modal.vue
Normal file
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<div ref="modal" @keydown.esc="close" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button @click="close" type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<h4 class="modal-title">
|
||||
{{ i18n.t("assets.file_versions_modal.title") }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div v-if="fileVersions" v-for="fileVersion in fileVersions" :key="fileVersion.id">
|
||||
<div class="flex w-full border border-sn-light-grey rounded mb-1.5 p-1.5 items-center">
|
||||
<div class="basis-3/4">
|
||||
<div class="mb-1.5">
|
||||
<span class="bg-sn-grey-300 me-2 px-2 py-0.5 rounded">v{{ fileVersion.attributes.version }}</span>
|
||||
<a :href="fileVersion.attributes.url" target="_blank">{{ fileVersion.attributes.filename }}</a>
|
||||
<small class="inline-block" v-if="fileVersion.attributes.restored_from_version">
|
||||
({{ i18n.t("assets.file_versions_modal.restored_from_version", { version: fileVersion.attributes.restored_from_version }) }})
|
||||
</small>
|
||||
</div>
|
||||
<div class="flex text-xs text-sn-grey justify-start">
|
||||
<div class="mr-3">{{ fileVersion.attributes.created_at }}</div>
|
||||
<div class="mr-3">{{ fileVersion.attributes.created_by.full_name }}</div>
|
||||
<div>{{ (fileVersion.attributes.byte_size/1024).toFixed(1) }}KB</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="basis-1/4 flex justify-end">
|
||||
<a class="btn btn-icon p-0" :href="fileVersion.attributes.url" target="_blank"><i class="sn-icon sn-icon-export"></i></a>
|
||||
<a class="btn btn-icon p-0 mx-3"><i class="sn-icon sn-icon-restore"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="sci-loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modalMixin from './modal_mixin';
|
||||
import axios from '../../packs/custom_axios';
|
||||
|
||||
export default {
|
||||
name: 'FileVersionsModal',
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mixins: [modalMixin],
|
||||
data() {
|
||||
return {
|
||||
fileVersions: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
axios.get(this.url).then((response) => {
|
||||
this.fileVersions = response.data.data;
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -8,10 +8,22 @@ module VersionedAttachments
|
|||
has_one_attached name, dependent: :detach
|
||||
has_many_attached "previous_#{name.to_s.pluralize}", dependent: :detach
|
||||
|
||||
define_method "attach_#{name}_version" do |*args, **options|
|
||||
define_method :"attach_#{name}_version" do |*args, **options|
|
||||
ActiveRecord::Base.transaction(requires_new: true) do
|
||||
__send__("previous_#{name.to_s.pluralize}").attach(__send__(name).blob) if __send__(name).attached?
|
||||
__send__(:"previous_#{name.to_s.pluralize}").attach(__send__(name).blob) if __send__(name).attached?
|
||||
__send__(name).attach(*args, **options)
|
||||
|
||||
new_blob = __send__(name).blob
|
||||
new_blob.metadata['created_by_id'] = last_modified_by_id
|
||||
new_blob.save!
|
||||
|
||||
# set version of current latest file if previous versions exist
|
||||
next unless __send__(:"previous_#{name.to_s.pluralize}").any?
|
||||
|
||||
new_version =
|
||||
(__send__(:"previous_#{name.to_s.pluralize}").last.blob.metadata['version'] || 1) + 1
|
||||
new_blob.metadata['version'] = new_version
|
||||
new_blob.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -138,7 +138,8 @@ class AssetSerializer < ActiveModel::Serializer
|
|||
load_asset: load_asset_path(object),
|
||||
asset_file: asset_file_url_path(object),
|
||||
marvin_js: marvin_js_asset_path(object),
|
||||
marvin_js_icon: image_path('icon_small/marvinjs.svg')
|
||||
marvin_js_icon: image_path('icon_small/marvinjs.svg'),
|
||||
versions: (asset_versions_path(object) if attached)
|
||||
}
|
||||
user = scope[:user] || @instance_options[:user]
|
||||
if can_manage_asset?(user, object)
|
||||
|
|
|
@ -4005,6 +4005,13 @@ en:
|
|||
inline_html: "Large"
|
||||
thumbnail_html: "Thumbnail"
|
||||
list_html: "List"
|
||||
versions: "Versions"
|
||||
file_versions_modal:
|
||||
title: "Version history"
|
||||
download: "Download"
|
||||
restore: "Restore"
|
||||
size: "Size"
|
||||
restored_from_version: "restored from v%{version}"
|
||||
rename_modal:
|
||||
title: "Rename file"
|
||||
min_length_error: "File name must be at least 1 character long."
|
||||
|
|
|
@ -861,6 +861,7 @@ Rails.application.routes.draw do
|
|||
get 'files/:id/edit', to: 'assets#edit', as: 'edit_asset'
|
||||
get 'files/:id/checksum', to: 'assets#checksum', as: 'asset_checksum'
|
||||
get 'files/:id/show', to: 'assets#show', as: 'asset_show'
|
||||
get 'files/:id/versions', to: 'assets#versions', as: 'asset_versions'
|
||||
patch 'files/:id/toggle_view_mode', to: 'assets#toggle_view_mode', as: 'toggle_view_mode'
|
||||
get 'files/:id/load_asset', to: 'assets#load_asset', as: 'load_asset'
|
||||
post 'files/:id/update_image', to: 'assets#update_image',
|
||||
|
|
Loading…
Reference in a new issue