Skip to content

Commit 5b2331d

Browse files
Merge pull request #51209 from nextcloud/backport/51146/stable30
[stable30] fix(files_trashbin): disable bulk download for trashbin
2 parents f69a4ff + d76e70c commit 5b2331d

5 files changed

Lines changed: 86 additions & 6 deletions

File tree

apps/files/src/actions/downloadAction.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export const action = new FileAction({
9696
displayName: () => t('files', 'Download'),
9797
iconSvgInline: () => ArrowDownSvg,
9898

99-
enabled(nodes: Node[]) {
99+
enabled(nodes: Node[], view: View) {
100100
if (nodes.length === 0) {
101101
return false
102102
}
@@ -109,6 +109,11 @@ export const action = new FileAction({
109109
return false
110110
}
111111

112+
// Trashbin does not allow batch download
113+
if (nodes.length > 1 && view.id === 'trashbin') {
114+
return false
115+
}
116+
112117
return nodes.every(isDownloadable)
113118
},
114119

cypress/e2e/files/FilesUtils.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const getActionsForFile = (filename: string) => getRowForFile(filename).f
1414
export const getActionButtonForFileId = (fileid: number) => getActionsForFileId(fileid).findByRole('button', { name: 'Actions' })
1515
export const getActionButtonForFile = (filename: string) => getActionsForFile(filename).findByRole('button', { name: 'Actions' })
1616

17-
const searchForActionInRow = (row: JQuery<HTMLElement>, actionId: string): Cypress.Chainable<JQuery<HTMLElement>> => {
17+
export const searchForActionInRow = (row: JQuery<HTMLElement>, actionId: string): Cypress.Chainable<JQuery<HTMLElement>> => {
1818
const action = row.find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
1919
if (action.length > 0) {
2020
cy.log('Found action in row')
@@ -31,6 +31,7 @@ export const getActionEntryForFileId = (fileid: number, actionId: string): Cypre
3131
return getRowForFileId(fileid).should('be.visible')
3232
.then(row => searchForActionInRow(row, actionId))
3333
}
34+
3435
export const getActionEntryForFile = (filename: string, actionId: string): Cypress.Chainable<JQuery<HTMLElement>> => {
3536
// If we cannot find the action in the row, it might be in the action menu
3637
return getRowForFile(filename).should('be.visible')
@@ -216,7 +217,11 @@ export const deleteFileWithRequest = (user: User, path: string) => {
216217
const requestToken = body.token
217218
cy.request({
218219
method: 'DELETE',
219-
url: `${Cypress.env('baseUrl')}/remote.php/dav/files/${user.userId}` + path,
220+
url: `${Cypress.env('baseUrl')}/remote.php/dav/files/${user.userId}${path}`,
221+
auth: {
222+
user: user.userId,
223+
password: user.password,
224+
},
220225
headers: {
221226
requestToken,
222227
},
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import type { User } from '@nextcloud/cypress'
7+
8+
// @ts-expect-error package has wrong typings
9+
import { deleteDownloadsFolderBeforeEach } from 'cypress-delete-downloads-folder'
10+
import { deleteFileWithRequest, getRowForFileId, selectAllFiles, triggerActionForFileId } from '../files/FilesUtils.ts'
11+
12+
describe('files_trashbin: download files', { testIsolation: true }, () => {
13+
let user: User
14+
const fileids: number[] = []
15+
16+
deleteDownloadsFolderBeforeEach()
17+
18+
before(() => {
19+
cy.createRandomUser().then(($user) => {
20+
user = $user
21+
22+
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/file.txt')
23+
.then(({ headers }) => fileids.push(Number.parseInt(headers['oc-fileid'])))
24+
.then(() => deleteFileWithRequest(user, '/file.txt'))
25+
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/other-file.txt')
26+
.then(({ headers }) => fileids.push(Number.parseInt(headers['oc-fileid'])))
27+
.then(() => deleteFileWithRequest(user, '/other-file.txt'))
28+
})
29+
})
30+
31+
beforeEach(() => {
32+
cy.login(user)
33+
cy.visit('/apps/files/trashbin')
34+
})
35+
36+
it('can download file', () => {
37+
getRowForFileId(fileids[0]).should('be.visible')
38+
getRowForFileId(fileids[1]).should('be.visible')
39+
40+
triggerActionForFileId(fileids[0], 'download')
41+
42+
const downloadsFolder = Cypress.config('downloadsFolder')
43+
cy.readFile(`${downloadsFolder}/file.txt`, { timeout: 15000 })
44+
.should('exist')
45+
.and('have.length.gt', 8)
46+
.and('equal', '<content>')
47+
})
48+
49+
it('can download a file using default action', () => {
50+
getRowForFileId(fileids[0])
51+
.should('be.visible')
52+
.findByRole('button', { name: 'Download' })
53+
.click({ force: true })
54+
55+
const downloadsFolder = Cypress.config('downloadsFolder')
56+
cy.readFile(`${downloadsFolder}/file.txt`, { timeout: 15000 })
57+
.should('exist')
58+
.and('have.length.gt', 8)
59+
.and('equal', '<content>')
60+
})
61+
62+
// TODO: Fix this as this dependens on the webdav zip folder plugin not working for trashbin (and never worked with old NC legacy download ajax as well)
63+
it('does not offer bulk download', () => {
64+
cy.get('[data-cy-files-list-row-checkbox]').should('have.length', 2)
65+
selectAllFiles()
66+
cy.get('.files-list__selected').should('have.text', '2 selected')
67+
cy.get('[data-cy-files-list-selection-action="restore"]').should('be.visible')
68+
cy.get('[data-cy-files-list-selection-action="download"]').should('not.exist')
69+
})
70+
})

dist/files-init.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-init.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)