mirror of
https://github.com/nextcloud/server.git
synced 2026-04-15 22:11:17 -04:00
feat(systemtags): add cypress tests and fix a few logic issues
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
This commit is contained in:
parent
db546e1f55
commit
d51cf4536c
11 changed files with 414 additions and 18 deletions
|
|
@ -21,7 +21,6 @@ use OCP\Util;
|
|||
use Sabre\DAV\Exception\BadRequest;
|
||||
use Sabre\DAV\Exception\Conflict;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
use Sabre\DAV\Exception\PreconditionFailed;
|
||||
use Sabre\DAV\Exception\UnsupportedMediaType;
|
||||
use Sabre\DAV\PropFind;
|
||||
use Sabre\DAV\PropPatch;
|
||||
|
|
@ -218,8 +217,8 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
$propFind->setPath(str_replace('systemtags-assigned/', 'systemtags/', $propFind->getPath()));
|
||||
}
|
||||
|
||||
$propFind->handle(FilesPlugin::GETETAG_PROPERTYNAME, function () use ($node): string|null {
|
||||
return $node->getSystemTag()->getETag();
|
||||
$propFind->handle(FilesPlugin::GETETAG_PROPERTYNAME, function () use ($node): string {
|
||||
return '"' . ($node->getSystemTag()->getETag() ?? '') . '"';
|
||||
});
|
||||
|
||||
$propFind->handle(self::ID_PROPERTYNAME, function () use ($node) {
|
||||
|
|
@ -379,7 +378,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
|
||||
if (isset($props[self::OBJECTIDS_PROPERTYNAME])) {
|
||||
$propValue = $props[self::OBJECTIDS_PROPERTYNAME];
|
||||
if (!($propValue instanceof SystemTagsObjectList) || count($propValue?->getObjects() ?: []) === 0) {
|
||||
if (!($propValue instanceof SystemTagsObjectList) || count($propValue->getObjects()) === 0) {
|
||||
throw new BadRequest('Invalid object-ids property');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
<NcCheckboxRadioSwitch v-else
|
||||
:aria-label="ariaLabel"
|
||||
:checked="isSelected"
|
||||
data-cy-files-list-row-checkbox
|
||||
@update:checked="onSelectionChange" />
|
||||
</td>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<tr class="files-list__row-head">
|
||||
<th class="files-list__column files-list__row-checkbox"
|
||||
@keyup.esc.exact="resetSelection">
|
||||
<NcCheckboxRadioSwitch v-bind="selectAllBind" @update:checked="onToggleAll" />
|
||||
<NcCheckboxRadioSwitch v-bind="selectAllBind" data-cy-files-list-selection-checkbox @update:checked="onToggleAll" />
|
||||
</th>
|
||||
|
||||
<!-- Columns display -->
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
<template>
|
||||
<div class="files-list__column files-list__row-actions-batch">
|
||||
<div class="files-list__column files-list__row-actions-batch" data-cy-files-list-selection-actions>
|
||||
<NcActions ref="actionsMenu"
|
||||
container="#app-content-vue"
|
||||
:disabled="!!loading || areSomeNodesLoading"
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
:key="action.id"
|
||||
:aria-label="action.displayName(nodes, currentView) + ' ' + t('files', '(selected)') /** TRANSLATORS: Selected like 'selected files and folders' */"
|
||||
:class="'files-list__row-actions-batch-' + action.id"
|
||||
:data-cy-files-list-selection-action="action.id"
|
||||
@click="onActionClick(action)">
|
||||
<template #icon>
|
||||
<NcLoadingIcon v-if="loading === action.id" :size="18" />
|
||||
|
|
|
|||
|
|
@ -23,22 +23,28 @@
|
|||
<!-- Search or create input -->
|
||||
<form class="systemtags-picker__create" @submit.stop.prevent="onNewTag">
|
||||
<NcTextField :value.sync="input"
|
||||
:label="t('systemtags', 'Search or create tag')">
|
||||
:label="t('systemtags', 'Search or create tag')"
|
||||
data-cy-systemtags-picker-input>
|
||||
<TagIcon :size="20" />
|
||||
</NcTextField>
|
||||
<NcButton :disabled="status === Status.CREATING_TAG" native-type="submit">
|
||||
<NcButton :disabled="status === Status.CREATING_TAG"
|
||||
native-type="submit"
|
||||
data-cy-systemtags-picker-input-submit>
|
||||
{{ t('systemtags', 'Create tag') }}
|
||||
</NcButton>
|
||||
</form>
|
||||
|
||||
<!-- Tags list -->
|
||||
<div v-if="filteredTags.length > 0" class="systemtags-picker__tags">
|
||||
<div v-if="filteredTags.length > 0"
|
||||
class="systemtags-picker__tags"
|
||||
data-cy-systemtags-picker-tags>
|
||||
<NcCheckboxRadioSwitch v-for="tag in filteredTags"
|
||||
:key="tag.id"
|
||||
:label="tag.displayName"
|
||||
:checked="isChecked(tag)"
|
||||
:indeterminate="isIndeterminate(tag)"
|
||||
:disabled="!tag.canAssign"
|
||||
:data-cy-systemtags-picker-tag="tag.id"
|
||||
@update:checked="onCheckUpdate(tag, $event)">
|
||||
{{ formatTagName(tag) }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
|
|
@ -61,10 +67,15 @@
|
|||
</template>
|
||||
|
||||
<template #actions>
|
||||
<NcButton :disabled="status !== Status.BASE" type="tertiary" @click="onCancel">
|
||||
<NcButton :disabled="status !== Status.BASE"
|
||||
type="tertiary"
|
||||
data-cy-systemtags-picker-button-cancel
|
||||
@click="onCancel">
|
||||
{{ t('systemtags', 'Cancel') }}
|
||||
</NcButton>
|
||||
<NcButton :disabled="!hasChanges || status !== Status.BASE" @click="onSubmit">
|
||||
<NcButton :disabled="!hasChanges || status !== Status.BASE"
|
||||
data-cy-systemtags-picker-button-submit
|
||||
@click="onSubmit">
|
||||
{{ t('systemtags', 'Apply changes') }}
|
||||
</NcButton>
|
||||
</template>
|
||||
|
|
@ -270,11 +281,11 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
formatTagName(tag: TagWithId): string {
|
||||
if (tag.userVisible) {
|
||||
if (!tag.userVisible) {
|
||||
return t('systemtags', '{displayName} (hidden)', { displayName: tag.displayName })
|
||||
}
|
||||
|
||||
if (tag.userAssignable) {
|
||||
if (!tag.userAssignable) {
|
||||
return t('systemtags', '{displayName} (restricted)', { displayName: tag.displayName })
|
||||
}
|
||||
|
||||
|
|
@ -317,6 +328,9 @@ export default defineComponent({
|
|||
const tag = await fetchTag(id)
|
||||
this.tags.push(tag)
|
||||
this.input = ''
|
||||
|
||||
// Check the newly created tag
|
||||
this.onCheckUpdate(tag, true)
|
||||
} catch (error) {
|
||||
showError((error as Error)?.message || t('systemtags', 'Failed to create tag'))
|
||||
} finally {
|
||||
|
|
|
|||
4
apps/systemtags/src/event-bus.d.ts
vendored
4
apps/systemtags/src/event-bus.d.ts
vendored
|
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import type { Node } from '@nextcloud/files'
|
||||
|
||||
declare module '@nextcloud/event-bus' {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const action = new FileAction({
|
|||
|
||||
// If the app is disabled, the action is not available anyway
|
||||
enabled(nodes) {
|
||||
if (nodes.length > 0) {
|
||||
if (nodes.length === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,11 +14,15 @@ export const getActionButtonForFile = (filename: string) => getActionsForFile(fi
|
|||
|
||||
export const triggerActionForFileId = (fileid: number, actionId: string) => {
|
||||
getActionButtonForFileId(fileid).click()
|
||||
cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).should('exist').click()
|
||||
// Getting the last button to avoid the one from popup fading out
|
||||
cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).last()
|
||||
.should('exist').click()
|
||||
}
|
||||
export const triggerActionForFile = (filename: string, actionId: string) => {
|
||||
getActionButtonForFile(filename).click()
|
||||
cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).should('exist').click()
|
||||
// Getting the last button to avoid the one from popup fading out
|
||||
cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).last()
|
||||
.should('exist').click()
|
||||
}
|
||||
|
||||
export const triggerInlineActionForFileId = (fileid: number, actionId: string) => {
|
||||
|
|
@ -28,6 +32,25 @@ export const triggerInlineActionForFile = (filename: string, actionId: string) =
|
|||
getActionsForFile(filename).get(`button[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`).should('exist').click()
|
||||
}
|
||||
|
||||
export const selectAllFiles = () => {
|
||||
cy.get('[data-cy-files-list-selection-checkbox]').findByRole('checkbox').click({ force: true })
|
||||
}
|
||||
export const selectRowForFile = (filename: string) => {
|
||||
getRowForFile(filename)
|
||||
.find('[data-cy-files-list-row-checkbox]')
|
||||
.findByRole('checkbox')
|
||||
.click({ force: true })
|
||||
.should('be.checked')
|
||||
cy.get('[data-cy-files-list-selection-checkbox]').findByRole('checkbox').should('satisfy', (elements) => {
|
||||
return elements.length === 1 && (elements[0].checked === true || elements[0].indeterminate === true)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
export const triggerSelectionAction = (actionId: string) => {
|
||||
cy.get(`button[data-cy-files-list-selection-action="${CSS.escape(actionId)}"]`).should('exist').click()
|
||||
}
|
||||
|
||||
export const moveFile = (fileName: string, dirPath: string) => {
|
||||
getRowForFile(fileName).should('be.visible')
|
||||
triggerActionForFile(fileName, 'move-copy')
|
||||
|
|
|
|||
354
cypress/e2e/systemtags/files-bulk-action.cy.ts
Normal file
354
cypress/e2e/systemtags/files-bulk-action.cy.ts
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { User } from '@nextcloud/cypress'
|
||||
import { randomBytes } from 'crypto'
|
||||
import { getRowForFile, selectAllFiles, selectRowForFile, triggerSelectionAction } from '../files/FilesUtils'
|
||||
import { createShare } from '../files_sharing/FilesSharingUtils'
|
||||
|
||||
let tags = {} as Record<string, number>
|
||||
const files = [
|
||||
'file1.txt',
|
||||
'file2.txt',
|
||||
'file3.txt',
|
||||
'file4.txt',
|
||||
'file5.txt',
|
||||
]
|
||||
|
||||
function resetTags() {
|
||||
tags = {}
|
||||
for (const tag in [0, 1, 2, 3, 4]) {
|
||||
tags[randomBytes(8).toString('base64').slice(0, 6)] = 0
|
||||
}
|
||||
|
||||
// delete any existing tags
|
||||
cy.runOccCommand('tag:list --output=json').then((output) => {
|
||||
Object.keys(JSON.parse(output.stdout)).forEach((id) => {
|
||||
cy.runOccCommand(`tag:delete ${id}`)
|
||||
})
|
||||
})
|
||||
|
||||
// create tags
|
||||
Object.keys(tags).forEach((tag) => {
|
||||
cy.runOccCommand(`tag:add ${tag} public --output=json`).then((output) => {
|
||||
tags[tag] = JSON.parse(output.stdout).id as number
|
||||
})
|
||||
})
|
||||
cy.log('Using tags', tags)
|
||||
}
|
||||
|
||||
function expectInlineTagForFile(file: string, tags: string[]) {
|
||||
getRowForFile(file)
|
||||
.find('[data-systemtags-fileid]')
|
||||
.findAllByRole('listitem')
|
||||
.should('have.length', tags.length)
|
||||
.each(tag => {
|
||||
expect(tag.text()).to.be.oneOf(tags)
|
||||
})
|
||||
}
|
||||
|
||||
function triggerTagManagementDialogAction() {
|
||||
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/').as('getTagsList')
|
||||
triggerSelectionAction('systemtags:bulk')
|
||||
cy.wait('@getTagsList')
|
||||
cy.get('[data-cy-systemtags-picker]').should('be.visible')
|
||||
}
|
||||
|
||||
describe('Systemtags: Files bulk action', { testIsolation: false }, () => {
|
||||
let snapshot: string
|
||||
let user1: User
|
||||
let user2: User
|
||||
|
||||
before(() => {
|
||||
cy.createRandomUser().then((_user1) => {
|
||||
user1 = _user1
|
||||
cy.createRandomUser().then((_user2) => {
|
||||
user2 = _user2
|
||||
})
|
||||
|
||||
files.forEach((file) => {
|
||||
cy.uploadContent(user1, new Blob([]), 'text/plain', '/' + file)
|
||||
})
|
||||
})
|
||||
|
||||
resetTags()
|
||||
})
|
||||
|
||||
it('Can assign tag to selection', () => {
|
||||
cy.login(user1)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
files.forEach((file) => {
|
||||
getRowForFile(file).should('be.visible')
|
||||
})
|
||||
selectRowForFile('file2.txt')
|
||||
selectRowForFile('file4.txt')
|
||||
|
||||
triggerTagManagementDialogAction()
|
||||
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5)
|
||||
|
||||
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData')
|
||||
cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData')
|
||||
|
||||
const tag = Object.keys(tags)[3]
|
||||
cy.get(`[data-cy-systemtags-picker-tag=${tags[tag]}]`).should('be.visible')
|
||||
.findByRole('checkbox').click({ force: true })
|
||||
cy.get('[data-cy-systemtags-picker-button-submit]').click()
|
||||
|
||||
cy.wait('@getTagData')
|
||||
cy.wait('@assignTagData')
|
||||
cy.get('[data-cy-systemtags-picker]').should('not.exist')
|
||||
|
||||
expectInlineTagForFile('file2.txt', [tag])
|
||||
expectInlineTagForFile('file4.txt', [tag])
|
||||
})
|
||||
|
||||
it('Can assign multiple tags to selection', () => {
|
||||
cy.login(user1)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
files.forEach((file) => {
|
||||
getRowForFile(file).should('be.visible')
|
||||
})
|
||||
selectAllFiles()
|
||||
|
||||
triggerTagManagementDialogAction()
|
||||
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5)
|
||||
|
||||
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData')
|
||||
cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData')
|
||||
|
||||
const prevTag = Object.keys(tags)[3]
|
||||
const tag1 = Object.keys(tags)[1]
|
||||
const tag2 = Object.keys(tags)[2]
|
||||
cy.get(`[data-cy-systemtags-picker-tag=${tags[tag1]}]`).should('be.visible')
|
||||
.findByRole('checkbox').click({ force: true })
|
||||
cy.get(`[data-cy-systemtags-picker-tag=${tags[tag2]}]`).should('be.visible')
|
||||
.findByRole('checkbox').click({ force: true })
|
||||
cy.get('[data-cy-systemtags-picker-button-submit]').click()
|
||||
|
||||
cy.wait('@getTagData')
|
||||
cy.wait('@assignTagData')
|
||||
cy.get('@getTagData.all').should('have.length', 2)
|
||||
cy.get('@assignTagData.all').should('have.length', 2)
|
||||
cy.get('[data-cy-systemtags-picker]').should('not.exist')
|
||||
|
||||
expectInlineTagForFile('file1.txt', [tag1, tag2])
|
||||
expectInlineTagForFile('file2.txt', [prevTag, tag1, tag2])
|
||||
expectInlineTagForFile('file3.txt', [tag1, tag2])
|
||||
expectInlineTagForFile('file4.txt', [prevTag, tag1, tag2])
|
||||
expectInlineTagForFile('file5.txt', [tag1, tag2])
|
||||
})
|
||||
|
||||
it('Can remove tag from selection', () => {
|
||||
cy.login(user1)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
files.forEach((file) => {
|
||||
getRowForFile(file).should('be.visible')
|
||||
})
|
||||
selectRowForFile('file1.txt')
|
||||
selectRowForFile('file3.txt')
|
||||
selectRowForFile('file4.txt')
|
||||
|
||||
triggerTagManagementDialogAction()
|
||||
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5)
|
||||
|
||||
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData')
|
||||
cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData')
|
||||
|
||||
const firstTag = Object.keys(tags)[3]
|
||||
const tag1 = Object.keys(tags)[1]
|
||||
const tag2 = Object.keys(tags)[2]
|
||||
cy.get(`[data-cy-systemtags-picker-tag=${tags[tag2]}]`).should('be.visible')
|
||||
.findByRole('checkbox').click({ force: true })
|
||||
cy.get('[data-cy-systemtags-picker-button-submit]').click()
|
||||
|
||||
cy.wait('@getTagData')
|
||||
cy.wait('@assignTagData')
|
||||
cy.get('[data-cy-systemtags-picker]').should('not.exist')
|
||||
|
||||
expectInlineTagForFile('file1.txt', [tag1])
|
||||
expectInlineTagForFile('file2.txt', [firstTag, tag1, tag2])
|
||||
expectInlineTagForFile('file3.txt', [tag1])
|
||||
expectInlineTagForFile('file4.txt', [firstTag, tag1])
|
||||
expectInlineTagForFile('file5.txt', [tag1, tag2])
|
||||
|
||||
})
|
||||
|
||||
it('Can remove multiple tags from selection', () => {
|
||||
cy.login(user1)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
files.forEach((file) => {
|
||||
getRowForFile(file).should('be.visible')
|
||||
})
|
||||
selectAllFiles()
|
||||
|
||||
triggerTagManagementDialogAction()
|
||||
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5)
|
||||
|
||||
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData')
|
||||
cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData')
|
||||
|
||||
cy.get('[data-cy-systemtags-picker-tag] input:indeterminate').should('exist')
|
||||
.click({ force: true, multiple: true })
|
||||
// indeterminate became checked
|
||||
cy.get('[data-cy-systemtags-picker-tag] input:checked').should('exist')
|
||||
.click({ force: true, multiple: true })
|
||||
// now all are unchecked
|
||||
cy.get('[data-cy-systemtags-picker-button-submit]').click()
|
||||
|
||||
cy.wait('@getTagData')
|
||||
cy.wait('@assignTagData')
|
||||
cy.get('@getTagData.all').should('have.length', 3)
|
||||
cy.get('@assignTagData.all').should('have.length', 3)
|
||||
cy.get('[data-cy-systemtags-picker]').should('not.exist')
|
||||
|
||||
expectInlineTagForFile('file1.txt', [])
|
||||
expectInlineTagForFile('file2.txt', [])
|
||||
expectInlineTagForFile('file3.txt', [])
|
||||
expectInlineTagForFile('file4.txt', [])
|
||||
expectInlineTagForFile('file5.txt', [])
|
||||
})
|
||||
|
||||
it('Can assign and remove multiple tags as a secondary user', () => {
|
||||
// Create new users
|
||||
cy.createRandomUser().then((_user1) => {
|
||||
user1 = _user1
|
||||
cy.createRandomUser().then((_user2) => {
|
||||
user2 = _user2
|
||||
})
|
||||
|
||||
files.forEach((file) => {
|
||||
cy.uploadContent(user1, new Blob([]), 'text/plain', '/' + file)
|
||||
})
|
||||
})
|
||||
|
||||
cy.login(user1)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
files.forEach((file) => {
|
||||
getRowForFile(file).should('be.visible')
|
||||
})
|
||||
selectAllFiles()
|
||||
|
||||
triggerTagManagementDialogAction()
|
||||
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5)
|
||||
|
||||
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData1')
|
||||
cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData1')
|
||||
|
||||
const tag1 = Object.keys(tags)[0]
|
||||
const tag2 = Object.keys(tags)[3]
|
||||
cy.get(`[data-cy-systemtags-picker-tag=${tags[tag1]}]`).should('be.visible')
|
||||
.findByRole('checkbox').click({ force: true })
|
||||
cy.get(`[data-cy-systemtags-picker-tag=${tags[tag2]}]`).should('be.visible')
|
||||
.findByRole('checkbox').click({ force: true })
|
||||
cy.get('[data-cy-systemtags-picker-button-submit]').click()
|
||||
|
||||
cy.wait('@getTagData1')
|
||||
cy.wait('@assignTagData1')
|
||||
cy.get('@getTagData1.all').should('have.length', 2)
|
||||
cy.get('@assignTagData1.all').should('have.length', 2)
|
||||
cy.get('[data-cy-systemtags-picker]').should('not.exist')
|
||||
|
||||
expectInlineTagForFile('file1.txt', [tag1, tag2])
|
||||
expectInlineTagForFile('file2.txt', [tag1, tag2])
|
||||
expectInlineTagForFile('file3.txt', [tag1, tag2])
|
||||
expectInlineTagForFile('file4.txt', [tag1, tag2])
|
||||
expectInlineTagForFile('file5.txt', [tag1, tag2])
|
||||
|
||||
createShare('file1.txt', user2.userId)
|
||||
createShare('file3.txt', user2.userId)
|
||||
|
||||
cy.login(user2)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
getRowForFile('file1.txt').should('be.visible')
|
||||
getRowForFile('file3.txt').should('be.visible')
|
||||
|
||||
expectInlineTagForFile('file1.txt', [tag1, tag2])
|
||||
expectInlineTagForFile('file3.txt', [tag1, tag2])
|
||||
|
||||
selectRowForFile('file1.txt')
|
||||
selectRowForFile('file3.txt')
|
||||
triggerTagManagementDialogAction()
|
||||
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5)
|
||||
|
||||
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData2')
|
||||
cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData2')
|
||||
|
||||
cy.get(`[data-cy-systemtags-picker-tag=${tags[tag1]}]`).should('be.visible')
|
||||
.findByRole('checkbox').click({ force: true })
|
||||
cy.get(`[data-cy-systemtags-picker-tag=${tags[tag2]}]`).should('be.visible')
|
||||
.findByRole('checkbox').click({ force: true })
|
||||
cy.get('[data-cy-systemtags-picker-button-submit]').click()
|
||||
|
||||
cy.wait('@getTagData2')
|
||||
cy.wait('@assignTagData2')
|
||||
cy.get('@getTagData2.all').should('have.length', 2)
|
||||
cy.get('@assignTagData2.all').should('have.length', 2)
|
||||
cy.get('[data-cy-systemtags-picker]').should('not.exist')
|
||||
|
||||
expectInlineTagForFile('file1.txt', [])
|
||||
expectInlineTagForFile('file3.txt', [])
|
||||
|
||||
cy.login(user1)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
expectInlineTagForFile('file1.txt', [])
|
||||
expectInlineTagForFile('file3.txt', [])
|
||||
})
|
||||
|
||||
it('Can create tag and assign files to it', () => {
|
||||
cy.createRandomUser().then((user1) => {
|
||||
files.forEach((file) => {
|
||||
cy.uploadContent(user1, new Blob([]), 'text/plain', '/' + file)
|
||||
})
|
||||
|
||||
cy.login(user1)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
files.forEach((file) => {
|
||||
getRowForFile(file).should('be.visible')
|
||||
})
|
||||
selectAllFiles()
|
||||
|
||||
triggerTagManagementDialogAction()
|
||||
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5)
|
||||
|
||||
cy.intercept('POST', '/remote.php/dav/systemtags').as('createTag')
|
||||
cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData')
|
||||
cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData')
|
||||
|
||||
const newTag = randomBytes(8).toString('base64').slice(0, 6)
|
||||
cy.get('[data-cy-systemtags-picker-input]').type(newTag)
|
||||
cy.get('[data-cy-systemtags-picker-input-submit]').click()
|
||||
|
||||
cy.wait('@createTag')
|
||||
cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 6)
|
||||
// Verify the new tag is selected by default
|
||||
cy.get('[data-cy-systemtags-picker-tag]').contains(newTag)
|
||||
.parents('[data-cy-systemtags-picker-tag]')
|
||||
.findByRole('checkbox', { hidden: true }).should('be.checked')
|
||||
|
||||
// Apply changes
|
||||
cy.get('[data-cy-systemtags-picker-button-submit]').click()
|
||||
|
||||
cy.wait('@getTagData')
|
||||
cy.wait('@assignTagData')
|
||||
cy.get('@getTagData.all').should('have.length', 1)
|
||||
cy.get('@assignTagData.all').should('have.length', 1)
|
||||
cy.get('[data-cy-systemtags-picker]').should('not.exist')
|
||||
|
||||
expectInlineTagForFile('file1.txt', [newTag])
|
||||
expectInlineTagForFile('file2.txt', [newTag])
|
||||
expectInlineTagForFile('file3.txt', [newTag])
|
||||
expectInlineTagForFile('file4.txt', [newTag])
|
||||
expectInlineTagForFile('file5.txt', [newTag])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -204,7 +204,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper {
|
|||
/**
|
||||
* Update the etag for the given tags.
|
||||
*
|
||||
* @param int[] $tagIds
|
||||
* @param string[] $tagIds
|
||||
*/
|
||||
private function updateEtagForTags(array $tagIds): void {
|
||||
// Update etag after assigning tags
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ interface ISystemTagObjectMapper {
|
|||
* @param string $tagId tag id
|
||||
* @param string $objectType object type
|
||||
* @param string[] $objectIds list of object ids
|
||||
*
|
||||
*
|
||||
* @throws TagNotFoundException if the tag does not exist
|
||||
* @since 31.0.0
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue