diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-01-21 19:52:31 +0100 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-01-25 15:07:52 +0100 |
commit | 4023f1e582a4020a438ee52e050ce9261b18db28 (patch) | |
tree | a0ffb40587ad6f2bbffcf6e74267acd19825828f /apps/files | |
parent | 2893d1b926d098a743d226590c3b96987843c6f8 (diff) | |
download | nextcloud-server-4023f1e582a4020a438ee52e050ce9261b18db28.tar.gz nextcloud-server-4023f1e582a4020a438ee52e050ce9261b18db28.zip |
fix(files): Make sure to add the `fileid` on favorite folders navigation entries
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/files')
-rw-r--r-- | apps/files/lib/Activity/Helper.php | 64 | ||||
-rw-r--r-- | apps/files/lib/Controller/ViewController.php | 11 | ||||
-rw-r--r-- | apps/files/src/views/Navigation.vue | 8 | ||||
-rw-r--r-- | apps/files/src/views/favorites.spec.ts | 13 | ||||
-rw-r--r-- | apps/files/src/views/favorites.ts | 47 |
5 files changed, 90 insertions, 53 deletions
diff --git a/apps/files/lib/Activity/Helper.php b/apps/files/lib/Activity/Helper.php index b9a5ae887ec..7bbaf44ab4c 100644 --- a/apps/files/lib/Activity/Helper.php +++ b/apps/files/lib/Activity/Helper.php @@ -4,6 +4,7 @@ * * @author Christoph Wurst <christoph@winzerhof-wurst.at> * @author Joas Schilling <coding@schilljs.com> + * @author Ferdinand Thiessen <opensource@fthiessen.de> * * @license AGPL-3.0 * @@ -23,30 +24,30 @@ namespace OCA\Files\Activity; use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\Node; use OCP\ITagManager; class Helper { /** If a user has a lot of favorites the query might get too slow and long */ public const FAVORITE_LIMIT = 50; - /** @var ITagManager */ - protected $tagManager; - - /** - * @param ITagManager $tagManager - */ - public function __construct(ITagManager $tagManager) { - $this->tagManager = $tagManager; + public function __construct( + protected ITagManager $tagManager, + protected IRootFolder $rootFolder, + ) { } /** - * Returns an array with the favorites + * Return an array with nodes marked as favorites * - * @param string $user - * @return array + * @param string $user User ID + * @param bool $foldersOnly Only return folders (default false) + * @return Node[] + * @psalm-return ($foldersOnly is true ? Folder[] : Node[]) * @throws \RuntimeException when too many or no favorites where found */ - public function getFavoriteFilePaths($user) { + public function getFavoriteNodes(string $user, bool $foldersOnly = false): array { $tags = $this->tagManager->load('files', [], false, $user); $favorites = $tags->getFavorites(); @@ -57,26 +58,45 @@ class Helper { } // Can not DI because the user is not known on instantiation - $rootFolder = \OC::$server->getUserFolder($user); - $folders = $items = []; + $userFolder = $this->rootFolder->getUserFolder($user); + $favoriteNodes = []; foreach ($favorites as $favorite) { - $nodes = $rootFolder->getById($favorite); + $nodes = $userFolder->getById($favorite); if (!empty($nodes)) { - /** @var \OCP\Files\Node $node */ $node = array_shift($nodes); - $path = substr($node->getPath(), strlen($user . '/files/')); - - $items[] = $path; - if ($node instanceof Folder) { - $folders[] = $path; + if (!$foldersOnly || $node instanceof Folder) { + $favoriteNodes[] = $node; } } } - if (empty($items)) { + if (empty($favoriteNodes)) { throw new \RuntimeException('No favorites', 1); } + return $favoriteNodes; + } + + /** + * Returns an array with the favorites + * + * @param string $user + * @return array + * @throws \RuntimeException when too many or no favorites where found + */ + public function getFavoriteFilePaths(string $user): array { + $userFolder = $this->rootFolder->getUserFolder($user); + $nodes = $this->getFavoriteNodes($user); + $folders = $items = []; + foreach ($nodes as $node) { + $path = $userFolder->getRelativePath($node->getPath()); + + $items[] = $path; + if ($node instanceof Folder) { + $folders[] = $path; + } + } + return [ 'items' => $items, 'folders' => $folders, diff --git a/apps/files/lib/Controller/ViewController.php b/apps/files/lib/Controller/ViewController.php index 7931686c92e..5172194dd8b 100644 --- a/apps/files/lib/Controller/ViewController.php +++ b/apps/files/lib/Controller/ViewController.php @@ -226,9 +226,14 @@ class ViewController extends Controller { // Get all the user favorites to create a submenu try { - $favElements = $this->activityHelper->getFavoriteFilePaths($userId); + $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['folders'] = []; + $favElements = []; } // If the file doesn't exists in the folder and @@ -260,7 +265,7 @@ 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['folders'] ?? []); + $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/views/Navigation.vue b/apps/files/src/views/Navigation.vue index 5ec650569b2..38f7a980a91 100644 --- a/apps/files/src/views/Navigation.vue +++ b/apps/files/src/views/Navigation.vue @@ -25,7 +25,7 @@ <template #list> <NcAppNavigationItem v-for="view in parentViews" :key="view.id" - allow-collapse + :allow-collapse="true" :data-cy-files-navigation-item="view.id" :exact="useExactRouteMatching(view)" :icon="view.iconClass" @@ -179,7 +179,7 @@ export default { * Like for the 'files' view this does not work because of optional 'fileid' param so /files and /files/1234 are both in the 'files' view * @param view The view to check */ - useExactRouteMatching(view: View) { + useExactRouteMatching(view: View): boolean { return this.childViews[view.id]?.length > 0 }, @@ -221,8 +221,8 @@ export default { */ generateToNavigation(view: View) { if (view.params) { - const { dir, fileid } = view.params - return { name: 'filelist', params: view.params, query: { dir, fileid } } + const { dir } = view.params + return { name: 'filelist', params: view.params, query: { dir } } } return { name: 'filelist', params: { view: view.id } } }, diff --git a/apps/files/src/views/favorites.spec.ts b/apps/files/src/views/favorites.spec.ts index 8fefb6d23b5..9497a7be1f9 100644 --- a/apps/files/src/views/favorites.spec.ts +++ b/apps/files/src/views/favorites.spec.ts @@ -82,9 +82,9 @@ describe('Favorites view definition', () => { test('Default with favorites', () => { const favoriteFolders = [ - '/foo', - '/bar', - '/foo/bar', + { fileid: 1, path: '/foo' }, + { fileid: 2, path: '/bar' }, + { fileid: 3, path: '/foo/bar' }, ] jest.spyOn(initialState, 'loadState').mockReturnValue(favoriteFolders) jest.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as Folder, contents: [] })) @@ -102,11 +102,12 @@ describe('Favorites view definition', () => { const favoriteView = favoriteFoldersViews[index] expect(favoriteView).toBeDefined() expect(favoriteView?.id).toBeDefined() - expect(favoriteView?.name).toBe(basename(folder)) + expect(favoriteView?.name).toBe(basename(folder.path)) expect(favoriteView?.icon).toBe('<svg>SvgMock</svg>') expect(favoriteView?.order).toBe(index) expect(favoriteView?.params).toStrictEqual({ - dir: folder, + dir: folder.path, + fileid: folder.fileid.toString(), view: 'favorites', }) expect(favoriteView?.parent).toBe('favorites') @@ -157,7 +158,7 @@ describe('Dynamic update of favourite folders', () => { test('Remove a favorite folder remove the entry from the navigation column', async () => { jest.spyOn(eventBus, 'emit') jest.spyOn(eventBus, 'subscribe') - jest.spyOn(initialState, 'loadState').mockReturnValue(['/Foo/Bar']) + jest.spyOn(initialState, 'loadState').mockReturnValue([{ fileid: 42, path: '/Foo/Bar' }]) jest.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as Folder, contents: [] })) registerFavoritesView() diff --git a/apps/files/src/views/favorites.ts b/apps/files/src/views/favorites.ts index 599aa191357..67c4fd58a86 100644 --- a/apps/files/src/views/favorites.ts +++ b/apps/files/src/views/favorites.ts @@ -19,11 +19,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -import { basename } from 'path' -import { getLanguage, translate as t } from '@nextcloud/l10n' -import { loadState } from '@nextcloud/initial-state' -import { Node, FileType, View, getNavigation } from '@nextcloud/files' +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 { getLanguage, translate as t } from '@nextcloud/l10n' +import { basename } from 'path' import FolderSvg from '@mdi/svg/svg/folder.svg?raw' import StarSvg from '@mdi/svg/svg/star.svg?raw' @@ -31,15 +33,22 @@ import { getContents } from '../services/Favorites' import { hashCode } from '../utils/hashUtils' import logger from '../logger' -export const generateFolderView = function(folder: string, index = 0): View { +// The return type of the initial state +interface IFavoriteFolder { + fileid: number + path: string +} + +export const generateFavoriteFolderView = function(folder: IFavoriteFolder, index = 0): View { return new View({ - id: generateIdFromPath(folder), - name: basename(folder), + id: generateIdFromPath(folder.path), + name: basename(folder.path), icon: FolderSvg, order: index, params: { - dir: folder, + dir: folder.path, + fileid: folder.fileid.toString(), view: 'favorites', }, @@ -57,8 +66,9 @@ export const generateIdFromPath = function(path: string): string { export default () => { // Load state in function for mock testing purposes - const favoriteFolders = loadState<string[]>('files', 'favoriteFolders', []) - const favoriteFoldersViews = favoriteFolders.map((folder, index) => generateFolderView(folder, index)) as View[] + const favoriteFolders = loadState<IFavoriteFolder[]>('files', 'favoriteFolders', []) + const favoriteFoldersViews = favoriteFolders.map((folder, index) => generateFavoriteFolderView(folder, index)) as View[] + logger.debug('Generating favorites view', { favoriteFolders }) const Navigation = getNavigation() Navigation.register(new View({ @@ -93,7 +103,7 @@ export default () => { return } - addPathToFavorites(node.path) + addToFavorites(node as Folder) }) /** @@ -118,9 +128,9 @@ export default () => { * update the order property of the existing views */ const updateAndSortViews = function() { - favoriteFolders.sort((a, b) => a.localeCompare(b, getLanguage(), { ignorePunctuation: true })) + favoriteFolders.sort((a, b) => a.path.localeCompare(b.path, getLanguage(), { ignorePunctuation: true })) favoriteFolders.forEach((folder, index) => { - const view = favoriteFoldersViews.find(view => view.id === generateIdFromPath(folder)) + const view = favoriteFoldersViews.find((view) => view.id === generateIdFromPath(folder.path)) if (view) { view.order = index } @@ -128,16 +138,17 @@ export default () => { } // Add a folder to the favorites paths array and update the views - const addPathToFavorites = function(path: string) { - const view = generateFolderView(path) + const addToFavorites = function(node: Folder) { + const newFavoriteFolder: IFavoriteFolder = { path: node.path, fileid: node.fileid! } + const view = generateFavoriteFolderView(newFavoriteFolder) // Skip if already exists - if (favoriteFolders.find(folder => folder === path)) { + if (favoriteFolders.find((folder) => folder.path === node.path)) { return } // Update arrays - favoriteFolders.push(path) + favoriteFolders.push(newFavoriteFolder) favoriteFoldersViews.push(view) // Update and sort views @@ -148,7 +159,7 @@ export default () => { // Remove a folder from the favorites paths array and update the views const removePathFromFavorites = function(path: string) { const id = generateIdFromPath(path) - const index = favoriteFolders.findIndex(folder => folder === path) + const index = favoriteFolders.findIndex((folder) => folder.path === path) // Skip if not exists if (index === -1) { |