This is for accessibility, to have the NcListItem (<li>) as a direct child of the <ul> Signed-off-by: Louis Chemineau <louis@chmn.me>tags/v29.0.0beta1
@@ -16,110 +16,78 @@ | |||
- along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
--> | |||
<template> | |||
<div> | |||
<NcListItem class="version" | |||
:name="versionLabel" | |||
:force-display-actions="true" | |||
data-files-versions-version | |||
@click="click"> | |||
<template #icon> | |||
<div v-if="!(loadPreview || previewLoaded)" class="version__image" /> | |||
<img v-else-if="(isCurrent || version.hasPreview) && !previewErrored" | |||
:src="version.previewUrl" | |||
alt="" | |||
decoding="async" | |||
fetchpriority="low" | |||
loading="lazy" | |||
class="version__image" | |||
@load="previewLoaded = true" | |||
@error="previewErrored = true"> | |||
<div v-else | |||
class="version__image"> | |||
<ImageOffOutline :size="20" /> | |||
</div> | |||
</template> | |||
<template #subname> | |||
<div class="version__info"> | |||
<span :title="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="enableLabeling" | |||
: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 && canView && canCompare" | |||
:close-after-click="true" | |||
@click="compareVersion"> | |||
<template #icon> | |||
<FileCompare :size="22" /> | |||
</template> | |||
{{ t('files_versions', 'Compare to current version') }} | |||
</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 && enableDeletion" | |||
: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('files_versions', 'Version name') }}</div> | |||
<NcTextField ref="labelInput" | |||
:value.sync="formVersionLabelValue" | |||
:placeholder="t('files_versions', 'Version name')" | |||
:label-outside="true" /> | |||
</label> | |||
<div class="version-label-modal__info"> | |||
{{ t('files_versions', '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> | |||
<NcListItem class="version" | |||
:name="versionLabel" | |||
:force-display-actions="true" | |||
data-files-versions-version | |||
@click="click"> | |||
<template #icon> | |||
<div v-if="!(loadPreview || previewLoaded)" class="version__image" /> | |||
<img v-else-if="(isCurrent || version.hasPreview) && !previewErrored" | |||
:src="version.previewUrl" | |||
alt="" | |||
decoding="async" | |||
fetchpriority="low" | |||
loading="lazy" | |||
class="version__image" | |||
@load="previewLoaded = true" | |||
@error="previewErrored = true"> | |||
<div v-else | |||
class="version__image"> | |||
<ImageOffOutline :size="20" /> | |||
</div> | |||
</template> | |||
<template #subname> | |||
<div class="version__info"> | |||
<span :title="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="enableLabeling" | |||
:close-after-click="true" | |||
@click="labelUpdate"> | |||
<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 && canView && canCompare" | |||
:close-after-click="true" | |||
@click="compareVersion"> | |||
<template #icon> | |||
<FileCompare :size="22" /> | |||
</template> | |||
{{ t('files_versions', 'Compare to current version') }} | |||
</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 && enableDeletion" | |||
:close-after-click="true" | |||
@click="deleteVersion"> | |||
<template #icon> | |||
<Delete :size="22" /> | |||
</template> | |||
{{ t('files_versions', 'Delete version') }} | |||
</NcActionButton> | |||
</template> | |||
</NcListItem> | |||
</template> | |||
<script> | |||
@@ -127,15 +95,11 @@ import BackupRestore from 'vue-material-design-icons/BackupRestore.vue' | |||
import Download from 'vue-material-design-icons/Download.vue' | |||
import FileCompare from 'vue-material-design-icons/FileCompare.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.vue' | |||
import ImageOffOutline from 'vue-material-design-icons/ImageOffOutline.vue' | |||
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' | |||
import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js' | |||
import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js' | |||
import NcModal from '@nextcloud/vue/dist/Components/NcModal.js' | |||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' | |||
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' | |||
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js' | |||
import moment from '@nextcloud/moment' | |||
import { translate as t } from '@nextcloud/l10n' | |||
@@ -149,14 +113,10 @@ export default { | |||
NcActionLink, | |||
NcActionButton, | |||
NcListItem, | |||
NcModal, | |||
NcButton, | |||
NcTextField, | |||
BackupRestore, | |||
Download, | |||
FileCompare, | |||
Pencil, | |||
Check, | |||
Delete, | |||
ImageOffOutline, | |||
}, | |||
@@ -180,7 +140,7 @@ export default { | |||
}, | |||
}, | |||
props: { | |||
/** @type {Vue.PropOptions<import('../utils/versions.js').Version>} */ | |||
/** @type {Vue.PropOptions<import('../utils/versions.ts').Version>} */ | |||
version: { | |||
type: Object, | |||
required: true, | |||
@@ -214,8 +174,6 @@ export default { | |||
return { | |||
previewLoaded: false, | |||
previewErrored: false, | |||
showVersionLabelForm: false, | |||
formVersionLabelValue: this.version.label, | |||
capabilities: loadState('core', 'capabilities', { files: { version_labeling: false, version_deletion: false } }), | |||
} | |||
}, | |||
@@ -268,23 +226,14 @@ export default { | |||
}, | |||
}, | |||
methods: { | |||
openVersionLabelModal() { | |||
this.showVersionLabelForm = true | |||
this.$nextTick(() => { | |||
this.$refs.labelInput.$el.getElementsByTagName('input')[0].focus() | |||
}) | |||
labelUpdate() { | |||
this.$emit('label-update-request') | |||
}, | |||
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) | |||
}, | |||
@@ -337,28 +286,4 @@ export default { | |||
color: var(--color-text-light); | |||
} | |||
} | |||
.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> |
@@ -0,0 +1,115 @@ | |||
<!-- | |||
- @copyright Copyright (c) 2024 Louis Chemineau <louis@chmn.me> | |||
- | |||
- @author Louis Chemineau <louis@chmn.me> | |||
- | |||
- @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> | |||
<form class="version-label-modal" | |||
@submit.prevent="setVersionLabel(innerVersionLabel)"> | |||
<label> | |||
<div class="version-label-modal__title">{{ t('files_versions', 'Version name') }}</div> | |||
<NcTextField ref="labelInput" | |||
:value.sync="innerVersionLabel" | |||
:placeholder="t('files_versions', 'Version name')" | |||
:label-outside="true" /> | |||
</label> | |||
<div class="version-label-modal__info"> | |||
{{ t('files_versions', 'Named versions are persisted, and excluded from automatic cleanups when your storage quota is full.') }} | |||
</div> | |||
<div class="version-label-modal__actions"> | |||
<NcButton :disabled="innerVersionLabel.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> | |||
</template> | |||
<script lang="ts"> | |||
import Check from 'vue-material-design-icons/Check.vue' | |||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' | |||
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' | |||
import { translate } from '@nextcloud/l10n' | |||
import { defineComponent } from 'vue' | |||
export default defineComponent({ | |||
name: 'VersionLabelForm', | |||
components: { | |||
NcButton, | |||
NcTextField, | |||
Check, | |||
}, | |||
props: { | |||
versionLabel: { | |||
type: String, | |||
default: '', | |||
}, | |||
}, | |||
data() { | |||
return { | |||
innerVersionLabel: this.versionLabel, | |||
} | |||
}, | |||
mounted() { | |||
this.$nextTick(() => { | |||
(this.$refs.labelInput as Vue).$el.getElementsByTagName('input')[0].focus() | |||
}) | |||
}, | |||
methods: { | |||
setVersionLabel(label: string) { | |||
this.$emit('label-update', label) | |||
}, | |||
t: translate, | |||
}, | |||
}) | |||
</script> | |||
<style scoped lang="scss"> | |||
.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> |
@@ -1,3 +1,6 @@ | |||
/* eslint-disable @typescript-eslint/no-explicit-any */ | |||
/* eslint-disable jsdoc/require-param */ | |||
/* eslint-disable jsdoc/require-jsdoc */ | |||
/** | |||
* @copyright 2022 Louis Chemineau <mlouis@chmn.me> | |||
* | |||
@@ -29,39 +32,35 @@ import { encodeFilePath } from '../../../files/src/utils/fileUtils.ts' | |||
import client from '../utils/davClient.js' | |||
import davRequest from '../utils/davRequest.js' | |||
import logger from '../utils/logger.js' | |||
import type { FileStat, ResponseDataDetailed } from 'webdav' | |||
/** | |||
* @typedef {object} Version | |||
* @property {string} fileId - The id of the file associated to the version. | |||
* @property {string} label - 'Current version' or '' | |||
* @property {string} filename - File name relative to the version DAV endpoint | |||
* @property {string} basename - A base name generated from the mtime | |||
* @property {string} mime - Empty for the current version, else the actual mime type of the version | |||
* @property {string} etag - Empty for the current version, else the actual mime type of the version | |||
* @property {string} size - Human readable size | |||
* @property {string} type - 'file' | |||
* @property {number} mtime - Version creation date as a timestamp | |||
* @property {string} permissions - Only readable: 'R' | |||
* @property {boolean} hasPreview - Whether the version has a preview | |||
* @property {string} previewUrl - Preview URL of the version | |||
* @property {string} url - Download URL of the version | |||
* @property {string} source - The WebDAV endpoint of the ressource | |||
* @property {string|null} fileVersion - The version id, null for the current version | |||
*/ | |||
export interface Version { | |||
fileId: string, // The id of the file associated to the version. | |||
label: string, // 'Current version' or '' | |||
filename: string, // File name relative to the version DAV endpoint | |||
basename: string, // A base name generated from the mtime | |||
mime: string, // Empty for the current version, else the actual mime type of the version | |||
etag: string, // Empty for the current version, else the actual mime type of the version | |||
size: string, // Human readable size | |||
type: string, // 'file' | |||
mtime: number, // Version creation date as a timestamp | |||
permissions: string, // Only readable: 'R' | |||
hasPreview: boolean, // Whether the version has a preview | |||
previewUrl: string, // Preview URL of the version | |||
url: string, // Download URL of the version | |||
source: string, // The WebDAV endpoint of the ressource | |||
fileVersion: string|null, // The version id, null for the current version | |||
} | |||
/** | |||
* @param fileInfo | |||
* @return {Promise<Version[]>} | |||
*/ | |||
export async function fetchVersions(fileInfo) { | |||
export async function fetchVersions(fileInfo: any): Promise<Version[]> { | |||
const path = `/versions/${getCurrentUser()?.uid}/versions/${fileInfo.id}` | |||
try { | |||
/** @type {import('webdav').ResponseDataDetailed<import('webdav').FileStat[]>} */ | |||
const response = await client.getDirectoryContents(path, { | |||
data: davRequest, | |||
details: true, | |||
}) | |||
}) as ResponseDataDetailed<FileStat[]> | |||
return response.data | |||
// Filter out root | |||
.filter(({ mime }) => mime !== '') | |||
@@ -74,10 +73,8 @@ export async function fetchVersions(fileInfo) { | |||
/** | |||
* Restore the given version | |||
* | |||
* @param {Version} version | |||
*/ | |||
export async function restoreVersion(version) { | |||
export async function restoreVersion(version: Version) { | |||
try { | |||
logger.debug('Restoring version', { url: version.url }) | |||
await client.moveFile( | |||
@@ -92,12 +89,8 @@ export async function restoreVersion(version) { | |||
/** | |||
* Format version | |||
* | |||
* @param {object} version - raw version received from the versions DAV endpoint | |||
* @param {object} fileInfo - file properties received from the files DAV endpoint | |||
* @return {Version} | |||
*/ | |||
function formatVersion(version, fileInfo) { | |||
function formatVersion(version: any, fileInfo: any): Version { | |||
const mtime = moment(version.lastmod).unix() * 1000 | |||
let previewUrl = '' | |||
@@ -132,11 +125,7 @@ function formatVersion(version, fileInfo) { | |||
} | |||
} | |||
/** | |||
* @param {Version} version | |||
* @param {string} newLabel | |||
*/ | |||
export async function setVersionLabel(version, newLabel) { | |||
export async function setVersionLabel(version: Version, newLabel: string) { | |||
return await client.customRequest( | |||
version.filename, | |||
{ | |||
@@ -156,9 +145,6 @@ export async function setVersionLabel(version, newLabel) { | |||
) | |||
} | |||
/** | |||
* @param {Version} version | |||
*/ | |||
export async function deleteVersion(version) { | |||
export async function deleteVersion(version: Version) { | |||
await client.deleteFile(version.filename) | |||
} |
@@ -16,30 +16,37 @@ | |||
- along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
--> | |||
<template> | |||
<VirtualScrolling :sections="sections" | |||
:header-height="0"> | |||
<template slot-scope="{visibleSections}"> | |||
<ul data-files-versions-versions-list> | |||
<template v-if="visibleSections.length === 1"> | |||
<Version v-for="(row) of visibleSections[0].rows" | |||
:key="row.items[0].mtime" | |||
:can-view="canView" | |||
:can-compare="canCompare" | |||
:load-preview="isActive" | |||
:version="row.items[0]" | |||
:file-info="fileInfo" | |||
:is-current="row.items[0].mtime === fileInfo.mtime" | |||
:is-first-version="row.items[0].mtime === initialVersionMtime" | |||
@click="openVersion" | |||
@compare="compareVersion" | |||
@restore="handleRestore" | |||
@label-update="handleLabelUpdate" | |||
@delete="handleDelete" /> | |||
</template> | |||
</ul> | |||
</template> | |||
<NcLoadingIcon v-if="loading" slot="loader" class="files-list-viewer__loader" /> | |||
</VirtualScrolling> | |||
<div class="versions-tab__container"> | |||
<VirtualScrolling :sections="sections" | |||
:header-height="0"> | |||
<template slot-scope="{visibleSections}"> | |||
<ul data-files-versions-versions-list> | |||
<template v-if="visibleSections.length === 1"> | |||
<Version v-for="(row) of visibleSections[0].rows" | |||
:key="row.items[0].mtime" | |||
:can-view="canView" | |||
:can-compare="canCompare" | |||
:load-preview="isActive" | |||
:version="row.items[0]" | |||
:file-info="fileInfo" | |||
:is-current="row.items[0].mtime === fileInfo.mtime" | |||
:is-first-version="row.items[0].mtime === initialVersionMtime" | |||
@click="openVersion" | |||
@compare="compareVersion" | |||
@restore="handleRestore" | |||
@label-update-request="handleLabelUpdateRequest(row.items[0])" | |||
@delete="handleDelete" /> | |||
</template> | |||
</ul> | |||
</template> | |||
<NcLoadingIcon v-if="loading" slot="loader" class="files-list-viewer__loader" /> | |||
</VirtualScrolling> | |||
<NcModal v-if="showVersionLabelForm" | |||
:title="t('files_versions', 'Name this version')" | |||
@close="showVersionLabelForm = false"> | |||
<VersionLabelForm :version-label="editedVersion.label" @label-update="handleLabelUpdate" /> | |||
</NcModal> | |||
</div> | |||
</template> | |||
<script> | |||
@@ -49,18 +56,22 @@ import { showError, showSuccess } from '@nextcloud/dialogs' | |||
import isMobile from '@nextcloud/vue/dist/Mixins/isMobile.js' | |||
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus' | |||
import { getCurrentUser } from '@nextcloud/auth' | |||
import { NcLoadingIcon } from '@nextcloud/vue' | |||
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' | |||
import NcModal from '@nextcloud/vue/dist/Components/NcModal.js' | |||
import { fetchVersions, deleteVersion, restoreVersion, setVersionLabel } from '../utils/versions.js' | |||
import { fetchVersions, deleteVersion, restoreVersion, setVersionLabel } from '../utils/versions.ts' | |||
import Version from '../components/Version.vue' | |||
import VirtualScrolling from '../components/VirtualScrolling.vue' | |||
import VersionLabelForm from '../components/VersionLabelForm.vue' | |||
export default { | |||
name: 'VersionTab', | |||
components: { | |||
Version, | |||
VirtualScrolling, | |||
VersionLabelForm, | |||
NcLoadingIcon, | |||
NcModal, | |||
}, | |||
mixins: [ | |||
isMobile, | |||
@@ -69,17 +80,12 @@ export default { | |||
return { | |||
fileInfo: null, | |||
isActive: false, | |||
/** @type {import('../utils/versions.js').Version[]} */ | |||
/** @type {import('../utils/versions.ts').Version[]} */ | |||
versions: [], | |||
loading: false, | |||
showVersionLabelForm: false, | |||
} | |||
}, | |||
mounted() { | |||
subscribe('files_versions:restore:restored', this.fetchVersions) | |||
}, | |||
beforeUnmount() { | |||
unsubscribe('files_versions:restore:restored', this.fetchVersions) | |||
}, | |||
computed: { | |||
sections() { | |||
const rows = this.orderedVersions.map(version => ({ key: version.mtime, height: 68, sectionKey: 'versions', items: [version] })) | |||
@@ -90,7 +96,7 @@ export default { | |||
* Order versions by mtime. | |||
* Put the current version at the top. | |||
* | |||
* @return {import('../utils/versions.js').Version[]} | |||
* @return {import('../utils/versions.ts').Version[]} | |||
*/ | |||
orderedVersions() { | |||
return [...this.versions].sort((a, b) => { | |||
@@ -146,6 +152,12 @@ export default { | |||
return !this.isMobile | |||
}, | |||
}, | |||
mounted() { | |||
subscribe('files_versions:restore:restored', this.fetchVersions) | |||
}, | |||
beforeUnmount() { | |||
unsubscribe('files_versions:restore:restored', this.fetchVersions) | |||
}, | |||
methods: { | |||
/** | |||
* Update current fileInfo and fetch new data | |||
@@ -180,7 +192,7 @@ export default { | |||
/** | |||
* Handle restored event from Version.vue | |||
* | |||
* @param {import('../utils/versions.js').Version} version | |||
* @param {import('../utils/versions.ts').Version} version | |||
*/ | |||
async handleRestore(version) { | |||
// Update local copy of fileInfo as rendering depends on it. | |||
@@ -220,26 +232,36 @@ export default { | |||
/** | |||
* Handle label-updated event from Version.vue | |||
* | |||
* @param {import('../utils/versions.js').Version} version | |||
* @param {string} newName | |||
* @param {import('../utils/versions.ts').Version} version | |||
*/ | |||
handleLabelUpdateRequest(version) { | |||
this.showVersionLabelForm = true | |||
this.editedVersion = version | |||
}, | |||
/** | |||
* Handle label-updated event from Version.vue | |||
* @param {string} newLabel | |||
*/ | |||
async handleLabelUpdate(version, newName) { | |||
const oldLabel = version.label | |||
version.label = newName | |||
async handleLabelUpdate(newLabel) { | |||
const oldLabel = this.editedVersion.label | |||
this.editedVersion.label = newLabel | |||
this.showVersionLabelForm = false | |||
try { | |||
await setVersionLabel(version, newName) | |||
await setVersionLabel(this.editedVersion, newLabel) | |||
this.editedVersion = null | |||
} catch (exception) { | |||
version.label = oldLabel | |||
showError(t('files_versions', 'Could not set version name')) | |||
this.editedVersion.label = oldLabel | |||
showError(this.t('files_versions', 'Could not set version label')) | |||
logger.error('Could not set version label', { exception }) | |||
} | |||
}, | |||
/** | |||
* Handle deleted event from Version.vue | |||
* | |||
* @param {import('../utils/versions.js').Version} version | |||
* @param {import('../utils/versions.ts').Version} version | |||
* @param {string} newName | |||
*/ | |||
async handleDelete(version) { | |||
@@ -292,3 +314,8 @@ export default { | |||
}, | |||
} | |||
</script> | |||
<style lang="scss"> | |||
.versions-tab__container { | |||
height: 100%; | |||
} | |||
</style> |