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
91 changes: 66 additions & 25 deletions apps/systemtags/src/components/SystemTags.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,56 @@
<NcLoadingIcon v-if="loadingTags"
:name="t('systemtags', 'Loading collaborative tags …')"
:size="32" />
<template v-else>
<NcSelectTags class="system-tags__select"
:input-label="t('systemtags', 'Search or create collaborative tags')"
:placeholder="t('systemtags', 'Collaborative tags …')"
:options="sortedTags"
:value="selectedTags"
:create-option="createOption"
:disabled="disabled"
:taggable="true"
:passthru="true"
:fetch-tags="false"
:loading="loading"
@input="handleInput"
@option:selected="handleSelect"
@option:created="handleCreate"
@option:deselected="handleDeselect">
<template #no-options>
{{ t('systemtags', 'No tags to select, type to create a new tag') }}
</template>
</NcSelectTags>
</template>

<NcSelectTags v-show="!loadingTags"
class="system-tags__select"
:input-label="t('systemtags', 'Search or create collaborative tags')"
:placeholder="t('systemtags', 'Collaborative tags …')"
:options="sortedTags"
:value="selectedTags"
:create-option="createOption"
:disabled="disabled"
:taggable="true"
:passthru="true"
:fetch-tags="false"
:loading="loading"
@input="handleInput"
@option:selected="handleSelect"
@option:created="handleCreate"
@option:deselected="handleDeselect">
<template #no-options>
{{ t('systemtags', 'No tags to select, type to create a new tag') }}
</template>
</NcSelectTags>
</div>
</template>

<script lang="ts">
// FIXME Vue TypeScript ESLint errors
/* eslint-disable */
import type { Node } from '@nextcloud/files'
import type { Tag, TagWithId } from '../types.js'

import Vue from 'vue'
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
import NcSelectTags from '@nextcloud/vue/components/NcSelectTags'

import { translate as t } from '@nextcloud/l10n'
import { emit, subscribe } from '@nextcloud/event-bus'
import { loadState } from '@nextcloud/initial-state'
import { showError } from '@nextcloud/dialogs'
import { t } from '@nextcloud/l10n'

import { defaultBaseTag } from '../utils.js'
import { fetchLastUsedTagIds, fetchTags } from '../services/api.js'
import { fetchNode } from '../../../files/src/services/WebdavClient.js'
import {
createTagForFile,
deleteTagForFile,
fetchTagsForFile,
setTagForFile,
} from '../services/files.js'
import logger from '../logger.js'

import { loadState } from '@nextcloud/initial-state'

import type { Tag, TagWithId } from '../types.js'

export default Vue.extend({
name: 'SystemTags',
Expand Down Expand Up @@ -125,6 +129,10 @@ export default Vue.extend({
},
},

mounted() {
subscribe('systemtags:node:updated', this.onTagUpdated)
},

methods: {
t,

Expand Down Expand Up @@ -179,6 +187,8 @@ export default Vue.extend({
showError(t('systemtags', 'Failed to select tag'))
}
this.loading = false

this.updateAndDispatchNodeTagsEvent(this.fileId)
},

async handleCreate(tag: Tag) {
Expand All @@ -197,6 +207,8 @@ export default Vue.extend({
showError(t('systemtags', 'Failed to create tag'))
}
this.loading = false

this.updateAndDispatchNodeTagsEvent(this.fileId)
},

async handleDeselect(tag: TagWithId) {
Expand All @@ -207,6 +219,35 @@ export default Vue.extend({
showError(t('systemtags', 'Failed to delete tag'))
}
this.loading = false

this.updateAndDispatchNodeTagsEvent(this.fileId)
},

async onTagUpdated(node: Node) {
if (node.fileid !== this.fileId) {
return
}

this.loadingTags = true
try {
this.selectedTags = await fetchTagsForFile(this.fileId)
} catch (error) {
showError(t('systemtags', 'Failed to load selected tags'))
}

this.loadingTags = false
},

async updateAndDispatchNodeTagsEvent(fileId: number) {
const path = window.OCA?.Files?.Sidebar?.file || ''
try {
const node = await fetchNode(path)
if (node) {
emit('systemtags:node:updated', node)
}
} catch (error) {
logger.error('Failed to fetch node for system tags update', { error, fileId })
}
},
},
})
Expand Down
85 changes: 51 additions & 34 deletions cypress/e2e/systemtags/files-inline-action.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ describe('Systemtags: Files integration', { testIsolation: true }, () => {
it('See first assigned tag in the file list', () => {
const tag = randomBytes(8).toString('base64')

cy.intercept('PROPFIND', `**/remote.php/dav/files/${user.userId}/file.txt`).as('getNode')
getRowForFile('file.txt').should('be.visible')
triggerActionForFile('file.txt', 'details')
cy.wait('@getNode')

cy.get('[data-cy-sidebar]')
.should('be.visible')
Expand All @@ -36,13 +38,14 @@ describe('Systemtags: Files integration', { testIsolation: true }, () => {
.click()

cy.intercept('PUT', '**/remote.php/dav/systemtags-relations/files/**').as('assignTag')
cy.get('[data-cy-sidebar]')
.findByRole('combobox', { name: /collaborative tags/i })
.should('be.visible')
.type(`${tag}{enter}`)

getCollaborativeTagsInput()
.type(`{selectAll}${tag}{enter}`)
cy.wait('@assignTag')
closeSidebar()
cy.wait('@getNode')

// Close the sidebar and reload to check the file list
closeSidebar()
cy.reload()

getRowForFile('file.txt')
Expand All @@ -56,8 +59,10 @@ describe('Systemtags: Files integration', { testIsolation: true }, () => {
const tag1 = randomBytes(5).toString('base64')
const tag2 = randomBytes(5).toString('base64')

cy.intercept('PROPFIND', `**/remote.php/dav/files/${user.userId}/file.txt`).as('getNode')
getRowForFile('file.txt').should('be.visible')
triggerActionForFile('file.txt', 'details')
cy.wait('@getNode')

cy.get('[data-cy-sidebar]')
.should('be.visible')
Expand All @@ -70,17 +75,20 @@ describe('Systemtags: Files integration', { testIsolation: true }, () => {
.click()

cy.intercept('PUT', '**/remote.php/dav/systemtags-relations/files/**').as('assignTag')
cy.get('[data-cy-sidebar]').within(() => {
cy.findByRole('combobox', { name: /collaborative tags/i })
.should('be.visible')
.type(`${tag1}{enter}`)
cy.wait('@assignTag')
cy.findByRole('combobox', { name: /collaborative tags/i })
.should('be.visible')
.type(`${tag2}{enter}`)
cy.wait('@assignTag')
})

// Assign first tag
getCollaborativeTagsInput()
.type(`{selectAll}${tag1}{enter}`)
cy.wait('@assignTag')
cy.wait('@getNode')

// Assign second tag
getCollaborativeTagsInput()
.type(`{selectAll}${tag2}{enter}`)
cy.wait('@assignTag')
cy.wait('@getNode')

// Close the sidebar and reload to check the file list
closeSidebar()
cy.reload()

Expand All @@ -97,11 +105,10 @@ describe('Systemtags: Files integration', { testIsolation: true }, () => {
const tag2 = randomBytes(4).toString('base64')
const tag3 = randomBytes(4).toString('base64')

cy.intercept('PROPFIND', `**/remote.php/dav/files/${user.userId}/file.txt`).as('getNode')
getRowForFile('file.txt').should('be.visible')

cy.intercept('PROPFIND', '**/remote.php/dav/**').as('sidebarLoaded')
triggerActionForFile('file.txt', 'details')
cy.wait('@sidebarLoaded')
cy.wait('@getNode')

cy.get('[data-cy-sidebar]')
.should('be.visible')
Expand All @@ -114,23 +121,26 @@ describe('Systemtags: Files integration', { testIsolation: true }, () => {
.click()

cy.intercept('PUT', '**/remote.php/dav/systemtags-relations/files/**').as('assignTag')
cy.get('[data-cy-sidebar]').within(() => {
cy.findByRole('combobox', { name: /collaborative tags/i })
.should('be.visible')
.type(`${tag1}{enter}`)
cy.wait('@assignTag')

cy.findByRole('combobox', { name: /collaborative tags/i })
.should('be.visible')
.type(`${tag2}{enter}`)
cy.wait('@assignTag')

cy.findByRole('combobox', { name: /collaborative tags/i })
.should('be.visible')
.type(`${tag3}{enter}`)
cy.wait('@assignTag')
})

// Assign first tag
getCollaborativeTagsInput()
.type(`{selectAll}${tag1}{enter}`)
cy.wait('@assignTag')
cy.wait('@getNode')

// Assign second tag
getCollaborativeTagsInput()
.type(`{selectAll}${tag2}{enter}`)
cy.wait('@assignTag')
cy.wait('@getNode')

// Assign third tag
getCollaborativeTagsInput()
.type(`{selectAll}${tag3}{enter}`)
cy.wait('@assignTag')
cy.wait('@getNode')

// Close the sidebar and reload to check the file list
closeSidebar()
cy.reload()

Expand All @@ -153,3 +163,10 @@ describe('Systemtags: Files integration', { testIsolation: true }, () => {
})
})
})

function getCollaborativeTagsInput(): Cypress.Chainable<JQuery<HTMLElement>> {
return cy.get('[data-cy-sidebar]')
.findByRole('combobox', { name: /collaborative tags/i })
.should('be.visible')
.should('not.have.attr', 'disabled', { timeout: 5000 })
}
4 changes: 2 additions & 2 deletions dist/files-sidebar.js

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

Loading