Signed-off-by: Louis Chemineau <louis@chmn.me>pull/35160/head
parent
e82bfba114
commit
629de6c8c9
@ -0,0 +1,36 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright Copyright (c) 2022 Louis Chmn <louis@chmn.me> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
* |
||||||
|
*/ |
||||||
|
namespace OCA\Files_Versions\Versions; |
||||||
|
|
||||||
|
/** |
||||||
|
* @since 26.0.0 |
||||||
|
*/ |
||||||
|
interface INameableVersionBackend { |
||||||
|
/** |
||||||
|
* Set the label for a version. |
||||||
|
* |
||||||
|
* @since 26.0.0 |
||||||
|
*/ |
||||||
|
public function setVersionLabel(IVersion $version, string $label): void; |
||||||
|
} |
@ -0,0 +1,302 @@ |
|||||||
|
<!-- |
||||||
|
- @copyright 2022 Carl Schwan <carl@carlschwan.eu> |
||||||
|
- @license AGPL-3.0-or-later |
||||||
|
- |
||||||
|
- This program is free software: you can redistribute it and/or modify |
||||||
|
- it under the terms of the GNU Affero General Public License as |
||||||
|
- published by the Free Software Foundation, either version 3 of the |
||||||
|
- License, or (at your option) any later version. |
||||||
|
- |
||||||
|
- This program is distributed in the hope that it will be useful, |
||||||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
- GNU Affero General Public License for more details. |
||||||
|
- |
||||||
|
- You should have received a copy of the GNU Affero General Public License |
||||||
|
- along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
--> |
||||||
|
<template> |
||||||
|
<div> |
||||||
|
<NcListItem class="version" |
||||||
|
:title="versionLabel" |
||||||
|
:href="downloadURL" |
||||||
|
:force-display-actions="true"> |
||||||
|
<template #icon> |
||||||
|
<img lazy="true" |
||||||
|
:src="previewURL" |
||||||
|
alt="" |
||||||
|
height="256" |
||||||
|
width="256" |
||||||
|
class="version__image"> |
||||||
|
</template> |
||||||
|
<template #subtitle> |
||||||
|
<div class="version__info"> |
||||||
|
<span v-tooltip="formattedDate">{{ version.mtime | humanDateFromNow }}</span> |
||||||
|
<!-- Separate dot to improve alignement --> |
||||||
|
<span class="version__info__size">•</span> |
||||||
|
<span class="version__info__size">{{ version.size | humanReadableSize }}</span> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<template #actions> |
||||||
|
<NcActionButton v-if="capabilities.files.version_labeling === true" |
||||||
|
:close-after-click="true" |
||||||
|
@click="openVersionLabelModal"> |
||||||
|
<template #icon> |
||||||
|
<Pencil :size="22" /> |
||||||
|
</template> |
||||||
|
{{ version.label === '' ? t('files_versions', 'Name this version') : t('files_versions', 'Edit version name') }} |
||||||
|
</NcActionButton> |
||||||
|
<NcActionButton v-if="!isCurrent" |
||||||
|
:close-after-click="true" |
||||||
|
@click="restoreVersion"> |
||||||
|
<template #icon> |
||||||
|
<BackupRestore :size="22" /> |
||||||
|
</template> |
||||||
|
{{ t('files_versions', 'Restore version') }} |
||||||
|
</NcActionButton> |
||||||
|
<NcActionLink :href="downloadURL" |
||||||
|
:close-after-click="true" |
||||||
|
:download="downloadURL"> |
||||||
|
<template #icon> |
||||||
|
<Download :size="22" /> |
||||||
|
</template> |
||||||
|
{{ t('files_versions', 'Download version') }} |
||||||
|
</NcActionLink> |
||||||
|
<NcActionButton v-if="!isCurrent" |
||||||
|
:close-after-click="true" |
||||||
|
@click="deleteVersion"> |
||||||
|
<template #icon> |
||||||
|
<Delete :size="22" /> |
||||||
|
</template> |
||||||
|
{{ t('files_versions', 'Delete version') }} |
||||||
|
</NcActionButton> |
||||||
|
</template> |
||||||
|
</NcListItem> |
||||||
|
<NcModal v-if="showVersionLabelForm" |
||||||
|
:title="t('files_versions', 'Name this version')" |
||||||
|
@close="showVersionLabelForm = false"> |
||||||
|
<form class="version-label-modal" |
||||||
|
@submit.prevent="setVersionLabel(formVersionLabelValue)"> |
||||||
|
<label> |
||||||
|
<div class="version-label-modal__title">{{ t('photos', 'Version name') }}</div> |
||||||
|
<NcTextField ref="labelInput" |
||||||
|
:value.sync="formVersionLabelValue" |
||||||
|
:placeholder="t('photos', 'Version name')" |
||||||
|
:label-outside="true" /> |
||||||
|
</label> |
||||||
|
|
||||||
|
<div class="version-label-modal__info"> |
||||||
|
{{ t('photos', 'Named versions are persisted, and excluded from automatic cleanups when your storage quota is full.') }} |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="version-label-modal__actions"> |
||||||
|
<NcButton :disabled="formVersionLabelValue.trim().length === 0" @click="setVersionLabel('')"> |
||||||
|
{{ t('files_versions', 'Remove version name') }} |
||||||
|
</NcButton> |
||||||
|
<NcButton type="primary" native-type="submit"> |
||||||
|
<template #icon> |
||||||
|
<Check /> |
||||||
|
</template> |
||||||
|
{{ t('files_versions', 'Save version name') }} |
||||||
|
</NcButton> |
||||||
|
</div> |
||||||
|
</form> |
||||||
|
</NcModal> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import BackupRestore from 'vue-material-design-icons/BackupRestore.vue' |
||||||
|
import Download from 'vue-material-design-icons/Download.vue' |
||||||
|
import Pencil from 'vue-material-design-icons/Pencil.vue' |
||||||
|
import Check from 'vue-material-design-icons/Check.vue' |
||||||
|
import Delete from 'vue-material-design-icons/Delete' |
||||||
|
import { NcActionButton, NcActionLink, NcListItem, NcModal, NcButton, NcTextField, Tooltip } from '@nextcloud/vue' |
||||||
|
import moment from '@nextcloud/moment' |
||||||
|
import { translate } from '@nextcloud/l10n' |
||||||
|
import { joinPaths } from '@nextcloud/paths' |
||||||
|
import { generateUrl } from '@nextcloud/router' |
||||||
|
import { loadState } from '@nextcloud/initial-state' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'Version', |
||||||
|
components: { |
||||||
|
NcActionLink, |
||||||
|
NcActionButton, |
||||||
|
NcListItem, |
||||||
|
NcModal, |
||||||
|
NcButton, |
||||||
|
NcTextField, |
||||||
|
BackupRestore, |
||||||
|
Download, |
||||||
|
Pencil, |
||||||
|
Check, |
||||||
|
Delete, |
||||||
|
}, |
||||||
|
directives: { |
||||||
|
tooltip: Tooltip, |
||||||
|
}, |
||||||
|
filters: { |
||||||
|
/** |
||||||
|
* @param {number} bytes |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
humanReadableSize(bytes) { |
||||||
|
return OC.Util.humanFileSize(bytes) |
||||||
|
}, |
||||||
|
/** |
||||||
|
* @param {number} timestamp |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
humanDateFromNow(timestamp) { |
||||||
|
return moment(timestamp).fromNow() |
||||||
|
}, |
||||||
|
}, |
||||||
|
props: { |
||||||
|
/** @type {Vue.PropOptions<import('../utils/versions.js').Version>} */ |
||||||
|
version: { |
||||||
|
type: Object, |
||||||
|
required: true, |
||||||
|
}, |
||||||
|
fileInfo: { |
||||||
|
type: Object, |
||||||
|
required: true, |
||||||
|
}, |
||||||
|
isCurrent: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
isFirstVersion: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
showVersionLabelForm: false, |
||||||
|
formVersionLabelValue: this.version.label, |
||||||
|
capabilities: loadState('core', 'capabilities', { files: { version_labeling: false } }), |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
/** |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
versionLabel() { |
||||||
|
if (this.isCurrent) { |
||||||
|
if (this.version.label === '') { |
||||||
|
return translate('files_versions', 'Current version') |
||||||
|
} else { |
||||||
|
return `${this.version.label} (${translate('files_versions', 'Current version')})` |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (this.isFirstVersion && this.version.label === '') { |
||||||
|
return translate('files_versions', 'Initial version') |
||||||
|
} |
||||||
|
|
||||||
|
return this.version.label |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
downloadURL() { |
||||||
|
if (this.isCurrent) { |
||||||
|
return joinPaths('/remote.php/webdav', this.fileInfo.path, this.fileInfo.name) |
||||||
|
} else { |
||||||
|
return this.version.url |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* @return {string} |
||||||
|
*/ |
||||||
|
previewURL() { |
||||||
|
if (this.isCurrent) { |
||||||
|
return generateUrl('/core/preview?fileId={fileId}&c={fileEtag}&x=250&y=250&forceIcon=0&a=0', { |
||||||
|
fileId: this.fileInfo.id, |
||||||
|
fileEtag: this.fileInfo.etag, |
||||||
|
}) |
||||||
|
} else { |
||||||
|
return this.version.preview |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
openVersionLabelModal() { |
||||||
|
this.showVersionLabelForm = true |
||||||
|
this.$nextTick(() => { |
||||||
|
this.$refs.labelInput.$el.getElementsByTagName('input')[0].focus() |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
restoreVersion() { |
||||||
|
this.$emit('restore', this.version) |
||||||
|
}, |
||||||
|
|
||||||
|
setVersionLabel(label) { |
||||||
|
this.formVersionLabelValue = label |
||||||
|
this.showVersionLabelForm = false |
||||||
|
this.$emit('label-update', this.version, label) |
||||||
|
}, |
||||||
|
|
||||||
|
deleteVersion() { |
||||||
|
this.$emit('delete', this.version) |
||||||
|
}, |
||||||
|
|
||||||
|
formattedDate() { |
||||||
|
return moment(this.version.mtime) |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.version { |
||||||
|
display: flex; |
||||||
|
flex-direction: row; |
||||||
|
|
||||||
|
&__info { |
||||||
|
display: flex; |
||||||
|
flex-direction: row; |
||||||
|
align-items: center; |
||||||
|
gap: 0.5rem; |
||||||
|
|
||||||
|
&__size { |
||||||
|
color: var(--color-text-lighter); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&__image { |
||||||
|
width: 3rem; |
||||||
|
height: 3rem; |
||||||
|
border: 1px solid var(--color-border); |
||||||
|
border-radius: var(--border-radius-large); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.version-label-modal { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
flex-direction: column; |
||||||
|
height: 250px; |
||||||
|
padding: 16px; |
||||||
|
|
||||||
|
&__title { |
||||||
|
margin-bottom: 12px; |
||||||
|
font-weight: 600; |
||||||
|
} |
||||||
|
|
||||||
|
&__info { |
||||||
|
margin-top: 12px; |
||||||
|
color: var(--color-text-maxcontrast); |
||||||
|
} |
||||||
|
|
||||||
|
&__actions { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
margin-top: 64px; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue