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
18 changes: 18 additions & 0 deletions apps/files/src/store/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,21 @@ export const useFilesStore = function(...args) {
// Otherwise, it means we receive an event for a node that is not in the store
fetchNode(node).then(n => this.updateNodes([n]))
},

// Handlers for legacy sidebar (no real nodes support)
onAddFavorite(node: Node) {
const ourNode = this.getNode(node.source)
if (ourNode) {
Vue.set(ourNode.attributes, 'favorite', 1)
}
},

onRemoveFavorite(node: Node) {
const ourNode = this.getNode(node.source)
if (ourNode) {
Vue.set(ourNode.attributes, 'favorite', 0)
}
},
},
})

Expand All @@ -172,6 +187,9 @@ export const useFilesStore = function(...args) {
subscribe('files:node:deleted', fileStore.onDeletedNode)
subscribe('files:node:updated', fileStore.onUpdatedNode)
subscribe('files:node:moved', fileStore.onMovedNode)
// legacy sidebar
subscribe('files:favorites:added', fileStore.onAddFavorite)
subscribe('files:favorites:removed', fileStore.onRemoveFavorite)

fileStore._initialized = true
}
Expand Down
22 changes: 13 additions & 9 deletions apps/files/src/views/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ import { getCurrentUser } from '@nextcloud/auth'
import { getCapabilities } from '@nextcloud/capabilities'
import { showError } from '@nextcloud/dialogs'
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
import { File, Folder, formatFileSize } from '@nextcloud/files'
import { davRemoteURL, davRootPath, File, Folder, formatFileSize } from '@nextcloud/files'
import { encodePath } from '@nextcloud/paths'
import { generateRemoteUrl, generateUrl } from '@nextcloud/router'
import { ShareType } from '@nextcloud/sharing'
Expand Down Expand Up @@ -375,10 +375,10 @@ export default {
},

/**
* Toggle favourite state
* Toggle favorite state
* TODO: better implementation
*
* @param {boolean} state favourited or not
* @param {boolean} state is favorite or not
*/
async toggleStarred(state) {
try {
Expand All @@ -401,17 +401,21 @@ export default {
*/
const isDir = this.fileInfo.type === 'dir'
const Node = isDir ? Folder : File
emit(state ? 'files:favorites:added' : 'files:favorites:removed', new Node({
const node = new Node({
fileid: this.fileInfo.id,
source: this.davPath,
root: `/files/${getCurrentUser().uid}`,
source: `${davRemoteURL}${davRootPath}${this.file}`,
root: davRootPath,
mime: isDir ? undefined : this.fileInfo.mimetype,
}))
attributes: {
favorite: 1,
},
})
emit(state ? 'files:favorites:added' : 'files:favorites:removed', node)

this.fileInfo.isFavourited = state
} catch (error) {
showError(t('files', 'Unable to change the favourite state of the file'))
logger.error('Unable to change favourite state', { error })
showError(t('files', 'Unable to change the favorite state of the file'))
logger.error('Unable to change favorite state', { error })
}
},

Expand Down
4 changes: 2 additions & 2 deletions apps/files/src/views/favorites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const registerFavoritesView = async () => {
favoriteFoldersViews.forEach(view => Navigation.register(view))

/**
* Update favourites navigation when a new folder is added
* Update favorites navigation when a new folder is added
*/
subscribe('files:favorites:added', (node: Node) => {
if (node.type !== FileType.Folder) {
Expand Down Expand Up @@ -99,7 +99,7 @@ export const registerFavoritesView = async () => {
})

/**
* Update favourites navigation when a folder is renamed
* Update favorites navigation when a folder is renamed
*/
subscribe('files:node:renamed', (node: Node) => {
if (node.type !== FileType.Folder) {
Expand Down
137 changes: 137 additions & 0 deletions cypress/e2e/files/favorites.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { User } from '@nextcloud/cypress'
import { getActionButtonForFile, getRowForFile, triggerActionForFile } from './FilesUtils'

describe('files: Favorites', { testIsolation: true }, () => {
let user: User

beforeEach(() => {
cy.createRandomUser().then(($user) => {
user = $user
cy.uploadContent(user, new Blob([]), 'text/plain', '/file.txt')
cy.mkdir(user, '/new folder')
cy.login(user)
cy.visit('/apps/files')
})
})

it('Mark file as favorite', () => {
// See file exists
getRowForFile('file.txt')
.should('exist')

cy.intercept('POST', '**/apps/files/api/v1/files/file.txt').as('addToFavorites')
// Click actions
getActionButtonForFile('file.txt').click({ force: true })
// See action is called 'Add to favorites'
cy.get('[data-cy-files-list-row-action="favorite"] > button').last()
.should('exist')
.and('have.text', 'Add to favorites')
.click({ force: true })
cy.wait('@addToFavorites')
// See favorites star
getRowForFile('file.txt')
.findByRole('img', { name: 'Favorite' })
.should('exist')
})

it('Un-mark file as favorite', () => {
// See file exists
getRowForFile('file.txt')
.should('exist')

cy.intercept('POST', '**/apps/files/api/v1/files/file.txt').as('addToFavorites')
// toggle favorite
triggerActionForFile('file.txt', 'favorite')
cy.wait('@addToFavorites')

// See favorites star
getRowForFile('file.txt')
.findByRole('img', { name: 'Favorite' })
.should('be.visible')

// Remove favorite
// click action button
getActionButtonForFile('file.txt').click({ force: true })
// See action is called 'Remove from favorites'
cy.get('[data-cy-files-list-row-action="favorite"] > button').last()
.should('exist')
.and('have.text', 'Remove from favorites')
.click({ force: true })
cy.wait('@addToFavorites')
// See no favorites star anymore
getRowForFile('file.txt')
.findByRole('img', { name: 'Favorite' })
.should('not.exist')
})

it('See favorite folders in navigation', () => {
cy.intercept('POST', '**/apps/files/api/v1/files/new%20folder').as('addToFavorites')

// see navigation has no entry
cy.get('[data-cy-files-navigation-item="favorites"]')
.should('be.visible')
.contains('new folder')
.should('not.exist')

// toggle favorite
triggerActionForFile('new folder', 'favorite')
cy.wait('@addToFavorites')

// See in navigation
cy.get('[data-cy-files-navigation-item="favorites"]')
.should('be.visible')
.contains('new folder')
.should('exist')

// toggle favorite
triggerActionForFile('new folder', 'favorite')
cy.wait('@addToFavorites')

// See no longer in navigation
cy.get('[data-cy-files-navigation-item="favorites"]')
.should('be.visible')
.contains('new folder')
.should('not.exist')
})

it('Mark file as favorite using the sidebar', () => {
// See file exists
getRowForFile('new folder')
.should('exist')
// see navigation has no entry
cy.get('[data-cy-files-navigation-item="favorites"]')
.should('be.visible')
.contains('new folder')
.should('not.exist')

cy.intercept('PROPPATCH', '**/remote.php/dav/files/*/new%20folder').as('addToFavorites')
// open sidebar
triggerActionForFile('new folder', 'details')
// open actions
cy.get('[data-cy-sidebar]')
.findByRole('button', { name: 'Actions' })
.click()
// trigger menu button
cy.findAllByRole('menu')
.findByRole('menuitem', { name: 'Add to favorites' })
.should('be.visible')
.click()
cy.wait('@addToFavorites')

// See favorites star
getRowForFile('new folder')
.findByRole('img', { name: 'Favorite' })
.should('be.visible')

// See folder in navigation
cy.get('[data-cy-files-navigation-item="favorites"]')
.should('be.visible')
.contains('new folder')
.should('exist')
})
})
2 changes: 1 addition & 1 deletion dist/files-init.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/files-main.js

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

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