Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 32 additions & 22 deletions apps/files_versions/src/components/Version.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,19 @@
<div class="version__info">
<div v-if="versionLabel"
class="version__info__label"
data-cy-files-version-label
:title="versionLabel">
{{ versionLabel }}
</div>
<div v-if="versionAuthor" class="version__info">
<div v-if="versionAuthor"
class="version__info"
data-cy-files-version-author-name>
<span v-if="versionLabel">•</span>
<NcAvatar class="avatar"
:user="version.author"
:size="16"
:disable-menu="true"
:disable-tooltip="true"
:size="20"
disable-menu
disable-tooltip
:show-user-status="false" />
<div>{{ versionAuthor }}</div>
</div>
Expand All @@ -53,7 +56,7 @@
<NcDateTime class="version__info__date"
relative-time="short"
:timestamp="version.mtime" />
<!-- Separate dot to improve alignement -->
<!-- Separate dot to improve alignment -->
<span>•</span>
<span>{{ humanReadableSize }}</span>
</div>
Expand Down Expand Up @@ -114,8 +117,18 @@
import type { PropType } from 'vue'
import type { Version } from '../utils/versions'

import { getCurrentUser } from '@nextcloud/auth'
import { Permission, formatFileSize } from '@nextcloud/files'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { joinPaths } from '@nextcloud/paths'
import { getRootUrl, generateUrl } from '@nextcloud/router'
import { defineComponent } from 'vue'

import axios from '@nextcloud/axios'
import moment from '@nextcloud/moment'
import logger from '../utils/logger'

import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
import Delete from 'vue-material-design-icons/Delete.vue'
import Download from 'vue-material-design-icons/Download.vue'
Expand All @@ -130,14 +143,6 @@ import NcDateTime from '@nextcloud/vue/dist/Components/NcDateTime.js'
import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'

import moment from '@nextcloud/moment'
import { getRootUrl, generateOcsUrl } from '@nextcloud/router'
import { joinPaths } from '@nextcloud/paths'
import { loadState } from '@nextcloud/initial-state'
import { Permission, formatFileSize } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import axios from '@nextcloud/axios'

const hasPermission = (permissions: number, permission: number): boolean => (permissions & permission) !== 0

export default defineComponent({
Expand Down Expand Up @@ -199,7 +204,7 @@ export default defineComponent({
previewLoaded: false,
previewErrored: false,
capabilities: loadState('core', 'capabilities', { files: { version_labeling: false, version_deletion: false } }),
versionAuthor: '',
versionAuthor: '' as string | null,
}
},

Expand Down Expand Up @@ -295,21 +300,26 @@ export default defineComponent({
},

async fetchDisplayName() {
// check to make sure that we have a valid author - in case database did not migrate, null author, etc.
if (this.version.author) {
this.versionAuthor = null
if (!this.version.author) {
return
}

if (this.version.author === getCurrentUser()?.uid) {
this.versionAuthor = t('files_versions', 'You')
} else {
try {
const { data } = await axios.get(generateOcsUrl(`/cloud/users/${this.version.author}`))
this.versionAuthor = data.ocs.data.displayname
} catch (e) {
// Promise got rejected - default to null author to not try to load author profile
this.versionAuthor = null
const { data } = await axios.post(generateUrl('/displaynames'), { users: [this.version.author] })
this.versionAuthor = data.users[this.version.author]
} catch (error) {
logger.warn('Could not load user display name', { error })
}
}
},

click() {
if (!this.canView) {
window.location = this.downloadURL
window.location.href = this.downloadURL
return
}
this.$emit('click', { version: this.version })
Expand Down
41 changes: 20 additions & 21 deletions apps/files_versions/src/views/VersionTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,27 @@
-->
<template>
<div class="versions-tab__container">
<VirtualScrolling :sections="sections"
<VirtualScrolling v-slot="{ visibleSections }"
: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>
<ul :aria-label="t('files_versions', 'File versions')" 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>
<NcLoadingIcon v-if="loading" slot="loader" class="files-list-viewer__loader" />
</VirtualScrolling>
<VersionLabelDialog v-if="editedVersion"
Expand Down
14 changes: 14 additions & 0 deletions cypress/e2e/files_versions/version_creation.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,18 @@ describe('Versions creation', () => {
cy.get('[data-files-versions-version]').eq(2).contains('Initial version')
})
})

it('See yourself as version author', () => {
cy.visit('/apps/files')
openVersionsPanel(randomFileName)

cy.findByRole('tabpanel', { name: 'Versions' })
.findByRole('list', { name: 'File versions' })
.findAllByRole('listitem')
.should('have.length', 3)
.first()
.find('[data-cy-files-version-author-name]')
.should('exist')
.and('contain.text', 'You')
})
})
46 changes: 46 additions & 0 deletions cypress/e2e/files_versions/version_sharing.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { User } from '@nextcloud/cypress'
import { openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts'
import { navigateToFolder, triggerActionForFile } from '../files/FilesUtils.ts'

describe('Versions on shares', () => {
const randomSharedFolderName = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 10)
const randomFileName = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 10) + '.txt'
const randomFilePath = `${randomSharedFolderName}/${randomFileName}`
let alice: User
let bob: User

before(() => {
cy.createRandomUser()
.then((user) => {
alice = user
})
.then(() => {
cy.mkdir(alice, `/${randomSharedFolderName}`)
return setupTestSharedFileFromUser(alice, randomSharedFolderName, {})
})
.then((user) => { bob = user })
.then(() => uploadThreeVersions(alice, randomFilePath))
})

it('See sharees display name as author', () => {
cy.login(bob)
cy.visit('/apps/files')

navigateToFolder(randomSharedFolderName)

triggerActionForFile(randomFileName, 'details')
cy.findByRole('tab', { name: 'Versions' }).click()

cy.findByRole('tabpanel', { name: 'Versions' })
.findByRole('list', { name: 'File versions' })
.findAllByRole('listitem')
.first()
.find('[data-cy-files-version-author-name]')
.should('be.visible')
.and('contain.text', alice.userId)
})
})
4 changes: 2 additions & 2 deletions dist/files_versions-files_versions.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/files_versions-files_versions.js.map

Large diffs are not rendered by default.

Loading