Merge pull request #46754 from nextcloud/backport/46648/stable28

This commit is contained in:
John Molakvoæ 2024-08-02 19:43:24 +02:00 committed by GitHub
commit e655d444f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 303 additions and 26 deletions

View file

@ -89,6 +89,6 @@ describe('Open in files action execute tests', () => {
// Silent action
expect(exec).toBe(null)
expect(goToRouteMock).toBeCalledTimes(1)
expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { dir: '/Foo', openfile: 'true' })
expect(goToRouteMock).toBeCalledWith(null, { fileid: '1', view: 'files' }, { dir: '/Foo', openfile: 'true' })
})
})

View file

@ -21,7 +21,7 @@
*/
import type { Node } from '@nextcloud/files'
import { registerFileAction, FileAction, DefaultType } from '@nextcloud/files'
import { registerFileAction, FileAction, DefaultType, FileType } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import { sharesViewId, sharedWithYouViewId, sharedWithOthersViewId, sharingByLinksViewId } from '../views/shares'
@ -41,10 +41,20 @@ export const action = new FileAction({
].includes(view.id),
async exec(node: Node) {
const isFolder = node.type === FileType.Folder
window.OCP.Files.Router.goToRoute(
null, // use default route
{ view: 'files', fileid: node.fileid },
{ dir: node.dirname, openfile: 'true' },
{
view: 'files',
fileid: String(node.fileid),
},
{
// If this node is a folder open the folder in files
dir: isFolder ? node.path : node.dirname,
// otherwise if this is a file, we should open it
openfile: isFolder ? undefined : 'true',
},
)
return null
},

View file

@ -46,6 +46,7 @@
@open-sharing-details="openShareDetailsForCustomSettings(share)" />
</div>
<NcButton class="sharing-entry__action"
data-cy-files-sharing-share-actions
:aria-label="t('files_sharing', 'Open Sharing Details')"
type="tertiary"
@click="openSharingDetails(share)">

View file

@ -19,6 +19,7 @@
<div ref="quickPermissions" class="sharingTabDetailsView__quick-permissions">
<div>
<NcCheckboxRadioSwitch :button-variant="true"
data-cy-files-sharing-share-permissions-bundle="read-only"
:checked.sync="sharingPermission"
:value="bundledPermissions.READ_ONLY.toString()"
name="sharing_permission_radio"
@ -31,6 +32,7 @@
</template>
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch :button-variant="true"
data-cy-files-sharing-share-permissions-bundle="upload-edit"
:checked.sync="sharingPermission"
:value="bundledPermissions.ALL.toString()"
name="sharing_permission_radio"
@ -48,6 +50,7 @@
</template>
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch v-if="allowsFileDrop"
data-cy-files-sharing-share-permissions-bundle="file-drop"
:button-variant="true"
:checked.sync="sharingPermission"
:value="bundledPermissions.FILE_DROP.toString()"
@ -62,6 +65,7 @@
</template>
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch :button-variant="true"
data-cy-files-sharing-share-permissions-bundle="custom"
:checked.sync="sharingPermission"
:value="'custom'"
name="sharing_permission_radio"
@ -146,7 +150,10 @@
@update:checked="queueUpdate('hideDownload')">
{{ t('files_sharing', 'Hide download') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch v-if="!isPublicShare" :disabled="!canSetDownload" :checked.sync="canDownload">
<NcCheckboxRadioSwitch v-if="!isPublicShare"
:disabled="!canSetDownload"
:checked.sync="canDownload"
data-cy-files-sharing-share-permissions-checkbox="download">
{{ t('files_sharing', 'Allow download') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch :checked.sync="writeNoteToRecipientIsChecked">
@ -163,21 +170,30 @@
</NcCheckboxRadioSwitch>
<section v-if="setCustomPermissions" class="custom-permissions-group">
<NcCheckboxRadioSwitch :disabled="!canRemoveReadPermission"
:checked.sync="hasRead">
:checked.sync="hasRead"
data-cy-files-sharing-share-permissions-checkbox="read">
{{ t('files_sharing', 'Read') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch v-if="isFolder" :disabled="!canSetCreate" :checked.sync="canCreate">
<NcCheckboxRadioSwitch v-if="isFolder"
:disabled="!canSetCreate"
:checked.sync="canCreate"
data-cy-files-sharing-share-permissions-checkbox="create">
{{ t('files_sharing', 'Create') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch :disabled="!canSetEdit" :checked.sync="canEdit">
<NcCheckboxRadioSwitch :disabled="!canSetEdit"
:checked.sync="canEdit"
data-cy-files-sharing-share-permissions-checkbox="update">
{{ t('files_sharing', 'Edit') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch v-if="config.isResharingAllowed && share.type !== SHARE_TYPES.SHARE_TYPE_LINK"
:disabled="!canSetReshare"
:checked.sync="canReshare">
:checked.sync="canReshare"
data-cy-files-sharing-share-permissions-checkbox="share">
{{ t('files_sharing', 'Share') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch :disabled="!canSetDelete" :checked.sync="canDelete">
<NcCheckboxRadioSwitch :disabled="!canSetDelete"
:checked.sync="canDelete"
data-cy-files-sharing-share-permissions-checkbox="delete">
{{ t('files_sharing', 'Delete') }}
</NcCheckboxRadioSwitch>
</section>
@ -200,10 +216,13 @@
<div class="sharingTabDetailsView__footer">
<div class="button-group">
<NcButton @click="$emit('close-sharing-details')">
<NcButton data-cy-files-sharing-share-editor-action="cancel"
@click="$emit('close-sharing-details')">
{{ t('files_sharing', 'Cancel') }}
</NcButton>
<NcButton type="primary" @click="saveShare">
<NcButton type="primary"
data-cy-files-sharing-share-editor-action="save"
@click="saveShare">
{{ shareButtonText }}
<template v-if="creating" #icon>
<NcLoadingIcon />

View file

@ -19,7 +19,7 @@
<NcListItem class="version"
:name="versionLabel"
:force-display-actions="true"
data-files-versions-version
:data-files-versions-version="version.fileVersion"
@click="click">
<template #icon>
<div v-if="!(loadPreview || previewLoaded)" class="version__image" />
@ -47,6 +47,7 @@
</template>
<template #actions>
<NcActionButton v-if="enableLabeling && hasUpdatePermissions"
data-cy-files-versions-version-action="label"
:close-after-click="true"
@click="labelUpdate">
<template #icon>
@ -55,6 +56,7 @@
{{ version.label === '' ? t('files_versions', 'Name this version') : t('files_versions', 'Edit version name') }}
</NcActionButton>
<NcActionButton v-if="!isCurrent && canView && canCompare"
data-cy-files-versions-version-action="compare"
:close-after-click="true"
@click="compareVersion">
<template #icon>
@ -63,6 +65,7 @@
{{ t('files_versions', 'Compare to current version') }}
</NcActionButton>
<NcActionButton v-if="!isCurrent && hasUpdatePermissions"
data-cy-files-versions-version-action="restore"
:close-after-click="true"
@click="restoreVersion">
<template #icon>
@ -71,6 +74,7 @@
{{ t('files_versions', 'Restore version') }}
</NcActionButton>
<NcActionLink v-if="isDownloadable"
data-cy-files-versions-version-action="download"
:href="downloadURL"
:close-after-click="true"
:download="downloadURL">
@ -80,6 +84,7 @@
{{ t('files_versions', 'Download version') }}
</NcActionLink>
<NcActionButton v-if="!isCurrent && enableDeletion && hasDeletePermissions"
data-cy-files-versions-version-action="delete"
:close-after-click="true"
@click="deleteVersion">
<template #icon>

View file

@ -0,0 +1,183 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/* eslint-disable jsdoc/require-jsdoc */
import { triggerActionForFile } from '../files/FilesUtils'
export interface ShareSetting {
read: boolean
update: boolean
delete: boolean
share: boolean
download: boolean
note: string
}
export function createShare(fileName: string, username: string, shareSettings: Partial<ShareSetting> = {}) {
openSharingPanel(fileName)
cy.get('#app-sidebar-vue').within(() => {
cy.get('#sharing-search-input').clear()
cy.intercept({ times: 1, method: 'GET', url: '**/apps/files_sharing/api/v1/sharees?*' }).as('userSearch')
cy.get('#sharing-search-input').type(username)
cy.wait('@userSearch')
})
cy.get(`[user="${username}"]`).click()
// HACK: Save the share and then update it, as permissions changes are currently not saved for new share.
cy.get('[data-cy-files-sharing-share-editor-action="save"]').click({ scrollBehavior: 'nearest' })
updateShare(fileName, 0, shareSettings)
}
export function updateShare(fileName: string, index: number, shareSettings: Partial<ShareSetting> = {}) {
openSharingPanel(fileName)
cy.intercept({ times: 1, method: 'PUT', url: '**/apps/files_sharing/api/v1/shares/*' }).as('updateShare')
cy.get('#app-sidebar-vue').within(() => {
cy.get('[data-cy-files-sharing-share-actions]').eq(index).click()
cy.get('[data-cy-files-sharing-share-permissions-bundle="custom"]').click()
if (shareSettings.download !== undefined) {
cy.get('[data-cy-files-sharing-share-permissions-checkbox="download"]').find('input').as('downloadCheckbox')
if (shareSettings.download) {
// Force:true because the checkbox is hidden by the pretty UI.
cy.get('@downloadCheckbox').check({ force: true, scrollBehavior: 'nearest' })
} else {
// Force:true because the checkbox is hidden by the pretty UI.
cy.get('@downloadCheckbox').uncheck({ force: true, scrollBehavior: 'nearest' })
}
}
if (shareSettings.read !== undefined) {
cy.get('[data-cy-files-sharing-share-permissions-checkbox="read"]').find('input').as('readCheckbox')
if (shareSettings.read) {
// Force:true because the checkbox is hidden by the pretty UI.
cy.get('@readCheckbox').check({ force: true, scrollBehavior: 'nearest' })
} else {
// Force:true because the checkbox is hidden by the pretty UI.
cy.get('@readCheckbox').uncheck({ force: true, scrollBehavior: 'nearest' })
}
}
if (shareSettings.update !== undefined) {
cy.get('[data-cy-files-sharing-share-permissions-checkbox="update"]').find('input').as('updateCheckbox')
if (shareSettings.update) {
// Force:true because the checkbox is hidden by the pretty UI.
cy.get('@updateCheckbox').check({ force: true, scrollBehavior: 'nearest' })
} else {
// Force:true because the checkbox is hidden by the pretty UI.
cy.get('@updateCheckbox').uncheck({ force: true, scrollBehavior: 'nearest' })
}
}
if (shareSettings.delete !== undefined) {
cy.get('[data-cy-files-sharing-share-permissions-checkbox="delete"]').find('input').as('deleteCheckbox')
if (shareSettings.delete) {
// Force:true because the checkbox is hidden by the pretty UI.
cy.get('@deleteCheckbox').check({ force: true, scrollBehavior: 'nearest' })
} else {
// Force:true because the checkbox is hidden by the pretty UI.
cy.get('@deleteCheckbox').uncheck({ force: true, scrollBehavior: 'nearest' })
}
}
if (shareSettings.note !== undefined) {
cy.findByRole('checkbox', { name: /note to recipient/i }).check({ force: true, scrollBehavior: 'nearest' })
cy.findByRole('textbox', { name: /note to recipient/i }).type(shareSettings.note)
}
cy.get('[data-cy-files-sharing-share-editor-action="save"]').click({ scrollBehavior: 'nearest' })
cy.wait('@updateShare')
})
}
export function openSharingPanel(fileName: string) {
triggerActionForFile(fileName, 'details')
cy.get('#app-sidebar-vue')
.get('[aria-controls="tab-sharing"]')
.click()
}
type FileRequestOptions = {
label?: string
note?: string
password?: string
/* YYYY-MM-DD format */
expiration?: string
}
/**
* Create a file request for a folder
* @param path The path of the folder, leading slash is required
* @param options The options for the file request
*/
export const createFileRequest = (path: string, options: FileRequestOptions = {}) => {
if (!path.startsWith('/')) {
throw new Error('Path must start with a slash')
}
// Navigate to the folder
cy.visit('/apps/files/files?dir=' + path)
// Open the file request dialog
cy.get('[data-cy-upload-picker] .action-item__menutoggle').first().click()
cy.contains('.upload-picker__menu-entry button', 'Create file request').click()
cy.get('[data-cy-file-request-dialog]').should('be.visible')
// Check and fill the first page options
cy.get('[data-cy-file-request-dialog-fieldset="label"]').should('be.visible')
cy.get('[data-cy-file-request-dialog-fieldset="destination"]').should('be.visible')
cy.get('[data-cy-file-request-dialog-fieldset="note"]').should('be.visible')
cy.get('[data-cy-file-request-dialog-fieldset="destination"] input').should('contain.value', path)
if (options.label) {
cy.get('[data-cy-file-request-dialog-fieldset="label"] input').type(`{selectall}${options.label}`)
}
if (options.note) {
cy.get('[data-cy-file-request-dialog-fieldset="note"] textarea').type(`{selectall}${options.note}`)
}
// Go to the next page
cy.get('[data-cy-file-request-dialog-controls="next"]').click()
cy.get('[data-cy-file-request-dialog-fieldset="expiration"] input[type="checkbox"]').should('exist')
cy.get('[data-cy-file-request-dialog-fieldset="expiration"] input[type="date"]').should('not.exist')
cy.get('[data-cy-file-request-dialog-fieldset="password"] input[type="checkbox"]').should('exist')
cy.get('[data-cy-file-request-dialog-fieldset="password"] input[type="password"]').should('not.exist')
if (options.expiration) {
cy.get('[data-cy-file-request-dialog-fieldset="expiration"] input[type="checkbox"]').check({ force: true })
cy.get('[data-cy-file-request-dialog-fieldset="expiration"] input[type="date"]').type(`{selectall}${options.expiration}`)
}
if (options.password) {
cy.get('[data-cy-file-request-dialog-fieldset="password"] input[type="checkbox"]').check({ force: true })
cy.get('[data-cy-file-request-dialog-fieldset="password"] input[type="password"]').type(`{selectall}${options.password}`)
}
// Create the file request
cy.get('[data-cy-file-request-dialog-controls="next"]').click()
// Get the file request URL
cy.get('[data-cy-file-request-dialog-fieldset="link"]').then(($link) => {
const url = $link.val()
cy.log(`File request URL: ${url}`)
cy.wrap(url).as('fileRequestUrl')
})
// Close
cy.get('[data-cy-file-request-dialog-controls="finish"]').click()
}
export const enterGuestName = (name: string) => {
cy.get('[data-cy-public-auth-prompt-dialog]').should('be.visible')
cy.get('[data-cy-public-auth-prompt-dialog-name]').should('be.visible')
cy.get('[data-cy-public-auth-prompt-dialog-submit]').should('be.visible')
cy.get('[data-cy-public-auth-prompt-dialog-name]').type(`{selectall}${name}`)
cy.get('[data-cy-public-auth-prompt-dialog-submit]').click()
cy.get('[data-cy-public-auth-prompt-dialog]').should('not.exist')
}

View file

@ -0,0 +1,59 @@
/*!
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { User } from '@nextcloud/cypress'
import { createShare } from './FilesSharingUtils.ts'
import { getRowForFile } from '../files/FilesUtils.ts'
describe('files_sharing: Files view', { testIsolation: true }, () => {
let user: User
let sharee: User
beforeEach(() => {
cy.createRandomUser().then(($user) => {
user = $user
})
cy.createRandomUser().then(($user) => {
sharee = $user
})
})
/**
* Regression test of https://github.com/nextcloud/server/issues/46108
*/
it('opens a shared folder when clicking on it', () => {
cy.mkdir(user, '/folder')
cy.uploadContent(user, new Blob([]), 'text/plain', '/folder/file')
cy.login(user)
cy.visit('/apps/files')
// share the folder
createShare('folder', sharee.userId, { read: true, download: true })
// visit the own shares
cy.visit('/apps/files/sharingout')
// see the shared folder
getRowForFile('folder').should('be.visible')
// click on the folder should open it in files
getRowForFile('folder').findByRole('button', { name: 'folder' }).click()
// See the URL has changed
cy.url().should('match', /apps\/files\/files\/.+dir=\/folder/)
// Content of the shared folder
getRowForFile('file').should('be.visible')
cy.logout()
// Now for the sharee
cy.login(sharee)
// visit shared files view
cy.visit('/apps/files/sharingin')
// see the shared folder
getRowForFile('folder').should('be.visible')
// click on the folder should open it in files
getRowForFile('folder').findByRole('button', { name: 'folder' }).click()
// See the URL has changed
cy.url().should('match', /apps\/files\/files\/.+dir=\/folder/)
// Content of the shared folder
getRowForFile('file').should('be.visible')
})
})

3
dist/3535-3535.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/3535-3535.js.map vendored Normal file

File diff suppressed because one or more lines are too long

3
dist/8985-8985.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long