diff options
author | Pytal <24800714+Pytal@users.noreply.github.com> | 2024-08-27 16:25:39 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-27 16:25:39 -0700 |
commit | b7212e3efbfdd5afcc4af12837a04efd5c54b478 (patch) | |
tree | ec7ac4a3afbc2b142a0a3fc78e967b5c4cc63b73 /apps/files | |
parent | a740e60afc4bc9d77ccb1c68095e3468ffc5db30 (diff) | |
parent | f48a7fffb7602ede4a1e1b635cb2b3f769eab2d6 (diff) | |
download | nextcloud-server-b7212e3efbfdd5afcc4af12837a04efd5c54b478.tar.gz nextcloud-server-b7212e3efbfdd5afcc4af12837a04efd5c54b478.zip |
Merge pull request #47400 from nextcloud/feat/load-more-than-50-faves
feat(files): Allow more than 50 favorite views
Diffstat (limited to 'apps/files')
-rw-r--r-- | apps/files/lib/Controller/ViewController.php | 15 | ||||
-rw-r--r-- | apps/files/src/init.ts | 2 | ||||
-rw-r--r-- | apps/files/src/views/favorites.spec.ts | 75 | ||||
-rw-r--r-- | apps/files/src/views/favorites.ts | 35 | ||||
-rw-r--r-- | apps/files/tests/Controller/ViewControllerTest.php | 64 |
5 files changed, 81 insertions, 110 deletions
diff --git a/apps/files/lib/Controller/ViewController.php b/apps/files/lib/Controller/ViewController.php index aa9aa81a814..e3d4c0a6aa0 100644 --- a/apps/files/lib/Controller/ViewController.php +++ b/apps/files/lib/Controller/ViewController.php @@ -8,7 +8,6 @@ namespace OCA\Files\Controller; use OC\Files\FilenameValidator; -use OCA\Files\Activity\Helper; use OCA\Files\AppInfo\Application; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadSearchPlugins; @@ -54,7 +53,6 @@ class ViewController extends Controller { private IUserSession $userSession, private IAppManager $appManager, private IRootFolder $rootFolder, - private Helper $activityHelper, private IInitialState $initialState, private ITemplateManager $templateManager, private UserConfig $userConfig, @@ -146,18 +144,6 @@ class ViewController extends Controller { $userId = $this->userSession->getUser()->getUID(); - // Get all the user favorites to create a submenu - try { - $userFolder = $this->rootFolder->getUserFolder($userId); - $favElements = $this->activityHelper->getFavoriteNodes($userId, true); - $favElements = array_map(fn (Folder $node) => [ - 'fileid' => $node->getId(), - 'path' => $userFolder->getRelativePath($node->getPath()), - ], $favElements); - } catch (\RuntimeException $e) { - $favElements = []; - } - // If the file doesn't exists in the folder and // exists in only one occurrence, redirect to that file // in the correct folder @@ -187,7 +173,6 @@ class ViewController extends Controller { $this->initialState->provideInitialState('storageStats', $storageInfo); $this->initialState->provideInitialState('config', $this->userConfig->getConfigs()); $this->initialState->provideInitialState('viewConfigs', $this->viewConfig->getConfigs()); - $this->initialState->provideInitialState('favoriteFolders', $favElements); // File sorting user config $filesSortingConfig = json_decode($this->config->getUserValue($userId, 'files', 'files_sorting_configs', '{}'), true); diff --git a/apps/files/src/init.ts b/apps/files/src/init.ts index 846f1049d5a..db4aec7fa06 100644 --- a/apps/files/src/init.ts +++ b/apps/files/src/init.ts @@ -23,7 +23,7 @@ import { entry as newFolderEntry } from './newMenu/newFolder.ts' import { entry as newTemplatesFolder } from './newMenu/newTemplatesFolder.ts' import { registerTemplateEntries } from './newMenu/newFromTemplate.ts' -import registerFavoritesView from './views/favorites' +import { registerFavoritesView } from './views/favorites.ts' import registerRecentView from './views/recent' import registerPersonalFilesView from './views/personal-files' import registerFilesView from './views/files' diff --git a/apps/files/src/views/favorites.spec.ts b/apps/files/src/views/favorites.spec.ts index b2aa292f936..64c3df0500a 100644 --- a/apps/files/src/views/favorites.spec.ts +++ b/apps/files/src/views/favorites.spec.ts @@ -3,16 +3,20 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { Folder, Navigation, getNavigation } from '@nextcloud/files' + +import type { Folder as CFolder, Navigation } from '@nextcloud/files' + +import * as filesUtils from '@nextcloud/files' import { CancelablePromise } from 'cancelable-promise' import { basename } from 'path' import { beforeEach, describe, expect, test, vi } from 'vitest' import * as eventBus from '@nextcloud/event-bus' -import * as initialState from '@nextcloud/initial-state' import { action } from '../actions/favoriteAction' import * as favoritesService from '../services/Favorites' -import registerFavoritesView from './favorites' +import { registerFavoritesView } from './favorites' + +const { Folder, getNavigation } = filesUtils vi.mock('@nextcloud/axios') @@ -37,11 +41,12 @@ describe('Favorites view definition', () => { expect(window._nc_navigation).toBeDefined() }) - test('Default empty favorite view', () => { + test('Default empty favorite view', async () => { vi.spyOn(eventBus, 'subscribe') - vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([])) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] })) - registerFavoritesView() + await registerFavoritesView() const favoritesView = Navigation.views.find(view => view.id === 'favorites') const favoriteFoldersViews = Navigation.views.filter(view => view.parent === 'favorites') @@ -64,16 +69,31 @@ describe('Favorites view definition', () => { expect(favoritesView?.getContents).toBeDefined() }) - test('Default with favorites', () => { + test('Default with favorites', async () => { const favoriteFolders = [ - { fileid: 1, path: '/foo' }, - { fileid: 2, path: '/bar' }, - { fileid: 3, path: '/foo/bar' }, + new Folder({ + id: 1, + root: '/files/admin', + source: 'http://nextcloud.local/remote.php/dav/files/admin/foo', + owner: 'admin', + }), + new Folder({ + id: 2, + root: '/files/admin', + source: 'http://nextcloud.local/remote.php/dav/files/admin/bar', + owner: 'admin', + }), + new Folder({ + id: 3, + root: '/files/admin', + source: 'http://nextcloud.local/remote.php/dav/files/admin/foo/bar', + owner: 'admin', + }), ] - vi.spyOn(initialState, 'loadState').mockReturnValue(favoriteFolders) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve(favoriteFolders)) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] })) - registerFavoritesView() + await registerFavoritesView() const favoritesView = Navigation.views.find(view => view.id === 'favorites') const favoriteFoldersViews = Navigation.views.filter(view => view.parent === 'favorites') @@ -91,7 +111,7 @@ describe('Favorites view definition', () => { expect(favoriteView?.order).toBe(index) expect(favoriteView?.params).toStrictEqual({ dir: folder.path, - fileid: folder.fileid.toString(), + fileid: String(folder.fileid), view: 'favorites', }) expect(favoriteView?.parent).toBe('favorites') @@ -112,10 +132,10 @@ describe('Dynamic update of favorite folders', () => { test('Add a favorite folder creates a new entry in the navigation', async () => { vi.spyOn(eventBus, 'emit') - vi.spyOn(initialState, 'loadState').mockReturnValue([]) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([])) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] })) - registerFavoritesView() + await registerFavoritesView() const favoritesView = Navigation.views.find(view => view.id === 'favorites') const favoriteFoldersViews = Navigation.views.filter(view => view.parent === 'favorites') @@ -140,10 +160,17 @@ describe('Dynamic update of favorite folders', () => { test('Remove a favorite folder remove the entry from the navigation column', async () => { vi.spyOn(eventBus, 'emit') - vi.spyOn(initialState, 'loadState').mockReturnValue([{ fileid: 42, path: '/Foo/Bar' }]) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) - - registerFavoritesView() + vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([ + new Folder({ + id: 42, + root: '/files/admin', + source: 'http://nextcloud.local/remote.php/dav/files/admin/Foo/Bar', + owner: 'admin', + }), + ])) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] })) + + await registerFavoritesView() let favoritesView = Navigation.views.find(view => view.id === 'favorites') let favoriteFoldersViews = Navigation.views.filter(view => view.parent === 'favorites') @@ -184,10 +211,10 @@ describe('Dynamic update of favorite folders', () => { test('Renaming a favorite folder updates the navigation', async () => { vi.spyOn(eventBus, 'emit') - vi.spyOn(initialState, 'loadState').mockReturnValue([]) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([])) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] })) - registerFavoritesView() + await registerFavoritesView() const favoritesView = Navigation.views.find(view => view.id === 'favorites') const favoriteFoldersViews = Navigation.views.filter(view => view.parent === 'favorites') diff --git a/apps/files/src/views/favorites.ts b/apps/files/src/views/favorites.ts index 3af8c49498f..c6846724bba 100644 --- a/apps/files/src/views/favorites.ts +++ b/apps/files/src/views/favorites.ts @@ -5,10 +5,9 @@ import type { Folder, Node } from '@nextcloud/files' import { subscribe } from '@nextcloud/event-bus' -import { FileType, View, getNavigation } from '@nextcloud/files' -import { loadState } from '@nextcloud/initial-state' +import { FileType, View, getFavoriteNodes, getNavigation } from '@nextcloud/files' import { getLanguage, translate as t } from '@nextcloud/l10n' -import { basename } from 'path' +import { client } from '../services/WebdavClient.ts' import FolderSvg from '@mdi/svg/svg/folder.svg?raw' import StarSvg from '@mdi/svg/svg/star.svg?raw' @@ -16,22 +15,17 @@ import { getContents } from '../services/Favorites' import { hashCode } from '../utils/hashUtils' import logger from '../logger' -// The return type of the initial state -interface IFavoriteFolder { - fileid: number - path: string -} - -export const generateFavoriteFolderView = function(folder: IFavoriteFolder, index = 0): View { +const generateFavoriteFolderView = function(folder: Folder, index = 0): View { return new View({ id: generateIdFromPath(folder.path), - name: basename(folder.path), + name: folder.displayname, icon: FolderSvg, order: index, + params: { dir: folder.path, - fileid: folder.fileid.toString(), + fileid: String(folder.fileid), view: 'favorites', }, @@ -43,16 +37,11 @@ export const generateFavoriteFolderView = function(folder: IFavoriteFolder, inde }) } -export const generateIdFromPath = function(path: string): string { +const generateIdFromPath = function(path: string): string { return `favorite-${hashCode(path)}` } -export default () => { - // Load state in function for mock testing purposes - const favoriteFolders = loadState<IFavoriteFolder[]>('files', 'favoriteFolders', []) - const favoriteFoldersViews = favoriteFolders.map((folder, index) => generateFavoriteFolderView(folder, index)) as View[] - logger.debug('Generating favorites view', { favoriteFolders }) - +export const registerFavoritesView = async () => { const Navigation = getNavigation() Navigation.register(new View({ id: 'favorites', @@ -70,6 +59,9 @@ export default () => { getContents, })) + const favoriteFolders = (await getFavoriteNodes(client)).filter(node => node.type === FileType.Folder) as Folder[] + const favoriteFoldersViews = favoriteFolders.map((folder, index) => generateFavoriteFolderView(folder, index)) as View[] + logger.debug('Generating favorites view', { favoriteFolders }) favoriteFoldersViews.forEach(view => Navigation.register(view)) /** @@ -137,8 +129,7 @@ export default () => { // Add a folder to the favorites paths array and update the views const addToFavorites = function(node: Folder) { - const newFavoriteFolder: IFavoriteFolder = { path: node.path, fileid: node.fileid! } - const view = generateFavoriteFolderView(newFavoriteFolder) + const view = generateFavoriteFolderView(node) // Skip if already exists if (favoriteFolders.find((folder) => folder.path === node.path)) { @@ -146,7 +137,7 @@ export default () => { } // Update arrays - favoriteFolders.push(newFavoriteFolder) + favoriteFolders.push(node) favoriteFoldersViews.push(view) // Update and sort views diff --git a/apps/files/tests/Controller/ViewControllerTest.php b/apps/files/tests/Controller/ViewControllerTest.php index e3ac7737d00..c1bc27d42b5 100644 --- a/apps/files/tests/Controller/ViewControllerTest.php +++ b/apps/files/tests/Controller/ViewControllerTest.php @@ -8,7 +8,6 @@ namespace OCA\Files\Tests\Controller; use OC\Files\FilenameValidator; -use OCA\Files\Activity\Helper; use OCA\Files\Controller\ViewController; use OCA\Files\Service\UserConfig; use OCA\Files\Service\ViewConfig; @@ -26,7 +25,7 @@ use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserSession; -use OCP\Share\IManager; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; /** @@ -35,38 +34,21 @@ use Test\TestCase; * @package OCA\Files\Tests\Controller */ class ViewControllerTest extends TestCase { - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ - private $request; - /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */ - private $urlGenerator; - /** @var IL10N */ - private $l10n; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $config; - /** @var IEventDispatcher */ - private $eventDispatcher; - /** @var ViewController|\PHPUnit\Framework\MockObject\MockObject */ - private $viewController; - /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */ - private $user; - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ - private $userSession; - /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */ - private $appManager; - /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject */ - private $rootFolder; - /** @var Helper|\PHPUnit\Framework\MockObject\MockObject */ - private $activityHelper; - /** @var IInitialState|\PHPUnit\Framework\MockObject\MockObject */ - private $initialState; - /** @var ITemplateManager|\PHPUnit\Framework\MockObject\MockObject */ - private $templateManager; - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ - private $shareManager; - /** @var UserConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $userConfig; - /** @var ViewConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $viewConfig; + private IRequest&MockObject $request; + private IURLGenerator&MockObject $urlGenerator; + private IL10N&MockObject $l10n; + private IConfig&MockObject $config; + private IEventDispatcher $eventDispatcher; + private IUser&MockObject $user; + private IUserSession&MockObject $userSession; + private IAppManager&MockObject $appManager; + private IRootFolder&MockObject $rootFolder; + private IInitialState&MockObject $initialState; + private ITemplateManager&MockObject $templateManager; + private UserConfig&MockObject $userConfig; + private ViewConfig&MockObject $viewConfig; + + private ViewController&MockObject $viewController; protected function setUp(): void { parent::setUp(); @@ -85,7 +67,6 @@ class ViewControllerTest extends TestCase { ->method('getUser') ->willReturn($this->user); $this->rootFolder = $this->getMockBuilder('\OCP\Files\IRootFolder')->getMock(); - $this->activityHelper = $this->createMock(Helper::class); $this->initialState = $this->createMock(IInitialState::class); $this->templateManager = $this->createMock(ITemplateManager::class); $this->userConfig = $this->createMock(UserConfig::class); @@ -104,7 +85,6 @@ class ViewControllerTest extends TestCase { $this->userSession, $this->appManager, $this->rootFolder, - $this->activityHelper, $this->initialState, $this->templateManager, $this->userConfig, @@ -162,18 +142,6 @@ class ViewControllerTest extends TestCase { $policy->addAllowedFrameDomain('\'self\''); $expected->setContentSecurityPolicy($policy); - $this->activityHelper->method('getFavoriteFilePaths') - ->with($this->user->getUID()) - ->willReturn([ - 'item' => [], - 'folders' => [ - '/test1', - '/test2/', - '/test3/sub4', - '/test5/sub6/', - ], - ]); - $this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView')); } |