aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files
diff options
context:
space:
mode:
authorPytal <24800714+Pytal@users.noreply.github.com>2024-08-27 16:25:39 -0700
committerGitHub <noreply@github.com>2024-08-27 16:25:39 -0700
commitb7212e3efbfdd5afcc4af12837a04efd5c54b478 (patch)
treeec7ac4a3afbc2b142a0a3fc78e967b5c4cc63b73 /apps/files
parenta740e60afc4bc9d77ccb1c68095e3468ffc5db30 (diff)
parentf48a7fffb7602ede4a1e1b635cb2b3f769eab2d6 (diff)
downloadnextcloud-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.php15
-rw-r--r--apps/files/src/init.ts2
-rw-r--r--apps/files/src/views/favorites.spec.ts75
-rw-r--r--apps/files/src/views/favorites.ts35
-rw-r--r--apps/files/tests/Controller/ViewControllerTest.php64
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'));
}