Skip to content

Commit c85b8aa

Browse files
authored
Merge pull request #51705 from nextcloud/fix/files-versions
fix(files_versions): correctly show version author also for shared files
2 parents e67eba5 + 4726400 commit c85b8aa

File tree

6 files changed

+114
-45
lines changed

6 files changed

+114
-45
lines changed

apps/files_versions/src/components/Version.vue

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,19 @@
3131
<div class="version__info">
3232
<div v-if="versionLabel"
3333
class="version__info__label"
34+
data-cy-files-version-label
3435
:title="versionLabel">
3536
{{ versionLabel }}
3637
</div>
37-
<div v-if="versionAuthor" class="version__info">
38+
<div v-if="versionAuthor"
39+
class="version__info"
40+
data-cy-files-version-author-name>
3841
<span v-if="versionLabel">•</span>
3942
<NcAvatar class="avatar"
4043
:user="version.author"
41-
:size="16"
42-
:disable-menu="true"
43-
:disable-tooltip="true"
44+
:size="20"
45+
disable-menu
46+
disable-tooltip
4447
:show-user-status="false" />
4548
<div>{{ versionAuthor }}</div>
4649
</div>
@@ -53,7 +56,7 @@
5356
<NcDateTime class="version__info__date"
5457
relative-time="short"
5558
:timestamp="version.mtime" />
56-
<!-- Separate dot to improve alignement -->
59+
<!-- Separate dot to improve alignment -->
5760
<span>•</span>
5861
<span>{{ humanReadableSize }}</span>
5962
</div>
@@ -114,8 +117,18 @@
114117
import type { PropType } from 'vue'
115118
import type { Version } from '../utils/versions'
116119
120+
import { getCurrentUser } from '@nextcloud/auth'
121+
import { Permission, formatFileSize } from '@nextcloud/files'
122+
import { loadState } from '@nextcloud/initial-state'
123+
import { t } from '@nextcloud/l10n'
124+
import { joinPaths } from '@nextcloud/paths'
125+
import { getRootUrl, generateUrl } from '@nextcloud/router'
117126
import { defineComponent } from 'vue'
118127
128+
import axios from '@nextcloud/axios'
129+
import moment from '@nextcloud/moment'
130+
import logger from '../utils/logger'
131+
119132
import BackupRestore from 'vue-material-design-icons/BackupRestore.vue'
120133
import Delete from 'vue-material-design-icons/Delete.vue'
121134
import Download from 'vue-material-design-icons/Download.vue'
@@ -130,14 +143,6 @@ import NcDateTime from '@nextcloud/vue/components/NcDateTime'
130143
import NcListItem from '@nextcloud/vue/components/NcListItem'
131144
import Tooltip from '@nextcloud/vue/directives/Tooltip'
132145
133-
import { Permission, formatFileSize } from '@nextcloud/files'
134-
import { loadState } from '@nextcloud/initial-state'
135-
import { t } from '@nextcloud/l10n'
136-
import { joinPaths } from '@nextcloud/paths'
137-
import { getRootUrl, generateOcsUrl } from '@nextcloud/router'
138-
import axios from '@nextcloud/axios'
139-
import moment from '@nextcloud/moment'
140-
141146
const hasPermission = (permissions: number, permission: number): boolean => (permissions & permission) !== 0
142147
143148
export default defineComponent({
@@ -295,21 +300,26 @@ export default defineComponent({
295300
},
296301
297302
async fetchDisplayName() {
298-
// check to make sure that we have a valid author - in case database did not migrate, null author, etc.
299-
if (this.version.author) {
303+
this.versionAuthor = null
304+
if (!this.version.author) {
305+
return
306+
}
307+
308+
if (this.version.author === getCurrentUser()?.uid) {
309+
this.versionAuthor = t('files_versions', 'You')
310+
} else {
300311
try {
301-
const { data } = await axios.get(generateOcsUrl(`/cloud/users/${this.version.author}`))
302-
this.versionAuthor = data.ocs.data.displayname
303-
} catch (e) {
304-
// Promise got rejected - default to null author to not try to load author profile
305-
this.versionAuthor = null
312+
const { data } = await axios.post(generateUrl('/displaynames'), { users: [this.version.author] })
313+
this.versionAuthor = data.users[this.version.author]
314+
} catch (error) {
315+
logger.warn('Could not load user display name', { error })
306316
}
307317
}
308318
},
309319
310320
click() {
311321
if (!this.canView) {
312-
window.location = this.downloadURL
322+
window.location.href = this.downloadURL
313323
return
314324
}
315325
this.$emit('click', { version: this.version })

apps/files_versions/src/views/VersionTab.vue

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,27 @@
44
-->
55
<template>
66
<div class="versions-tab__container">
7-
<VirtualScrolling :sections="sections"
7+
<VirtualScrolling v-slot="{ visibleSections }"
8+
:sections="sections"
89
:header-height="0">
9-
<template slot-scope="{visibleSections}">
10-
<ul data-files-versions-versions-list>
11-
<template v-if="visibleSections.length === 1">
12-
<Version v-for="(row) of visibleSections[0].rows"
13-
:key="row.items[0].mtime"
14-
:can-view="canView"
15-
:can-compare="canCompare"
16-
:load-preview="isActive"
17-
:version="row.items[0]"
18-
:file-info="fileInfo"
19-
:is-current="row.items[0].mtime === fileInfo.mtime"
20-
:is-first-version="row.items[0].mtime === initialVersionMtime"
21-
@click="openVersion"
22-
@compare="compareVersion"
23-
@restore="handleRestore"
24-
@label-update-request="handleLabelUpdateRequest(row.items[0])"
25-
@delete="handleDelete" />
26-
</template>
27-
</ul>
28-
</template>
10+
<ul :aria-label="t('files_versions', 'File versions')" data-files-versions-versions-list>
11+
<template v-if="visibleSections.length === 1">
12+
<Version v-for="(row) of visibleSections[0].rows"
13+
:key="row.items[0].mtime"
14+
:can-view="canView"
15+
:can-compare="canCompare"
16+
:load-preview="isActive"
17+
:version="row.items[0]"
18+
:file-info="fileInfo"
19+
:is-current="row.items[0].mtime === fileInfo.mtime"
20+
:is-first-version="row.items[0].mtime === initialVersionMtime"
21+
@click="openVersion"
22+
@compare="compareVersion"
23+
@restore="handleRestore"
24+
@label-update-request="handleLabelUpdateRequest(row.items[0])"
25+
@delete="handleDelete" />
26+
</template>
27+
</ul>
2928
<NcLoadingIcon v-if="loading" slot="loader" class="files-list-viewer__loader" />
3029
</VirtualScrolling>
3130
<VersionLabelDialog v-if="editedVersion"

cypress/e2e/files_versions/version_creation.cy.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,18 @@ describe('Versions creation', () => {
3030
cy.get('[data-files-versions-version]').eq(2).contains('Initial version')
3131
})
3232
})
33+
34+
it('See yourself as version author', () => {
35+
cy.visit('/apps/files')
36+
openVersionsPanel(randomFileName)
37+
38+
cy.findByRole('tabpanel', { name: 'Versions' })
39+
.findByRole('list', { name: 'File versions' })
40+
.findAllByRole('listitem')
41+
.should('have.length', 3)
42+
.first()
43+
.find('[data-cy-files-version-author-name]')
44+
.should('exist')
45+
.and('contain.text', 'You')
46+
})
3347
})
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
import type { User } from '@nextcloud/cypress'
6+
import { openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts'
7+
import { navigateToFolder, triggerActionForFile } from '../files/FilesUtils.ts'
8+
9+
describe('Versions on shares', () => {
10+
const randomSharedFolderName = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 10)
11+
const randomFileName = Math.random().toString(36).replace(/[^a-z]+/g, '').substring(0, 10) + '.txt'
12+
const randomFilePath = `${randomSharedFolderName}/${randomFileName}`
13+
let alice: User
14+
let bob: User
15+
16+
before(() => {
17+
cy.createRandomUser()
18+
.then((user) => {
19+
alice = user
20+
})
21+
.then(() => {
22+
cy.mkdir(alice, `/${randomSharedFolderName}`)
23+
return setupTestSharedFileFromUser(alice, randomSharedFolderName, {})
24+
})
25+
.then((user) => { bob = user })
26+
.then(() => uploadThreeVersions(alice, randomFilePath))
27+
})
28+
29+
it('See sharees display name as author', () => {
30+
cy.login(bob)
31+
cy.visit('/apps/files')
32+
33+
navigateToFolder(randomSharedFolderName)
34+
35+
triggerActionForFile(randomFileName, 'details')
36+
cy.findByRole('tab', { name: 'Versions' }).click()
37+
38+
cy.findByRole('tabpanel', { name: 'Versions' })
39+
.findByRole('list', { name: 'File versions' })
40+
.findAllByRole('listitem')
41+
.first()
42+
.find('[data-cy-files-version-author-name]')
43+
.should('be.visible')
44+
.and('contain.text', alice.userId)
45+
})
46+
})

dist/files_versions-files_versions.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files_versions-files_versions.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)