Skip to content

Commit df0b7a3

Browse files
authored
Merge pull request #58277 from nextcloud/backport/58273/stable33
2 parents dd2c8d9 + 7eda9ce commit df0b7a3

26 files changed

Lines changed: 605 additions & 518 deletions

apps/files/lib/Controller/ApiController.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,38 @@ private function getChildren(array $nodes, int $depth = 1, int $currentDepth = 0
275275
return $children;
276276
}
277277

278+
/**
279+
* Get all parents with their contents of the current folder.
280+
*
281+
* @param Folder $currentFolder - The current folder to get the parents for
282+
* @param string $root - The root path to stop at
283+
* @param array $children - The children of the current folder to include in the response
284+
*/
285+
private function getParents(Folder $currentFolder, string $root, array $children): array {
286+
$parentFolder = $currentFolder->getParent();
287+
$parentContent = array_filter($parentFolder->getDirectoryListing(), fn (Node $node) => $node instanceof Folder);
288+
$parentData = array_map(fn (Folder $node) => [
289+
'id' => $node->getId(),
290+
'basename' => basename($node->getPath()),
291+
'displayName' => $node->getName(),
292+
'children' => $node->getId() === $currentFolder->getId()
293+
? $children
294+
: [],
295+
], $parentContent);
296+
297+
if ($parentFolder->getPath() === $root) {
298+
return array_values($parentData);
299+
}
300+
301+
return $this->getParents($parentFolder, $root, array_values($parentData));
302+
}
303+
278304
/**
279305
* Returns the folder tree of the user
280306
*
281307
* @param string $path The path relative to the user folder
282308
* @param int $depth The depth of the tree
309+
* @param bool $withParents Whether to include parent folders in the response
283310
*
284311
* @return JSONResponse<Http::STATUS_OK, FilesFolderTree, array{}>|JSONResponse<Http::STATUS_UNAUTHORIZED|Http::STATUS_BAD_REQUEST|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
285312
*
@@ -291,7 +318,7 @@ private function getChildren(array $nodes, int $depth = 1, int $currentDepth = 0
291318
#[NoAdminRequired]
292319
#[ApiRoute(verb: 'GET', url: '/api/v1/folder-tree')]
293320
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
294-
public function getFolderTree(string $path = '/', int $depth = 1): JSONResponse {
321+
public function getFolderTree(string $path = '/', int $depth = 1, bool $withParents = false): JSONResponse {
295322
$user = $this->userSession->getUser();
296323
if (!($user instanceof IUser)) {
297324
return new JSONResponse([
@@ -310,6 +337,10 @@ public function getFolderTree(string $path = '/', int $depth = 1): JSONResponse
310337
}
311338
$nodes = $node->getDirectoryListing();
312339
$tree = $this->getChildren($nodes, $depth);
340+
341+
if ($withParents && $path !== '/') {
342+
$tree = $this->getParents($node, $userFolderPath, $tree);
343+
}
313344
} catch (NotFoundException $e) {
314345
return new JSONResponse([
315346
'message' => $this->l10n->t('Folder not found'),

apps/files/openapi.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2647,6 +2647,15 @@
26472647
"default": 1
26482648
}
26492649
},
2650+
{
2651+
"name": "withParents",
2652+
"in": "query",
2653+
"description": "Whether to include parent folders in the response",
2654+
"schema": {
2655+
"type": "boolean",
2656+
"default": false
2657+
}
2658+
},
26502659
{
26512660
"name": "OCS-APIRequest",
26522661
"in": "header",

apps/files/src/components/FilesNavigationItem.vue

Lines changed: 0 additions & 186 deletions
This file was deleted.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<script setup lang="ts">
7+
import type { IView } from '@nextcloud/files'
8+
9+
import { getCanonicalLocale, getLanguage, t } from '@nextcloud/l10n'
10+
import { computed } from 'vue'
11+
import NcAppNavigationList from '@nextcloud/vue/components/NcAppNavigationList'
12+
import FilesNavigationListItem from './FilesNavigationListItem.vue'
13+
import { useVisibleViews } from '../composables/useViews.ts'
14+
15+
const views = useVisibleViews()
16+
const rootViews = computed(() => views.value
17+
.filter((view) => !view.parent)
18+
.sort(sortViews))
19+
20+
const collator = Intl.Collator(
21+
[getLanguage(), getCanonicalLocale()],
22+
{ numeric: true, usage: 'sort' },
23+
)
24+
25+
/**
26+
* Sort views by their order property if available, otherwise sort alphabetically by name.
27+
*
28+
* @param a - first view
29+
* @param b - second view
30+
*/
31+
function sortViews(a: IView, b: IView): number {
32+
if (a.order !== undefined && b.order === undefined) {
33+
return -1
34+
} else if (a.order === undefined && b.order !== undefined) {
35+
return 1
36+
}
37+
return collator.compare(a.name, b.name)
38+
}
39+
</script>
40+
41+
<template>
42+
<NcAppNavigationList
43+
:class="$style.filesNavigationList"
44+
:aria-label="t('files', 'Views')">
45+
<FilesNavigationListItem
46+
v-for="view in rootViews"
47+
:key="view.id"
48+
:view="view" />
49+
</NcAppNavigationList>
50+
</template>
51+
52+
<style module>
53+
.filesNavigationList {
54+
height: 100%; /* Fill all available space for sticky views */
55+
}
56+
</style>

0 commit comments

Comments
 (0)