share: show directory structure

pull/880/head
Clément Saccoccio 2023-10-19 22:12:26 +03:00
parent 85a8f32da1
commit c85a611651
10 changed files with 51 additions and 34 deletions

View File

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
function getWildcard($param)
{
return [
@ -34,7 +36,6 @@ return [
w(['name' => 'Page#tags', 'url' => '/tags/{name}', 'verb' => 'GET'], 'name'),
// Public folder share
['name' => 'Public#showShare', 'url' => '/s/{token}', 'verb' => 'GET'],
[
'name' => 'Public#showAuthenticate',
'url' => '/s/{token}/authenticate/{redirect}',
@ -45,6 +46,7 @@ return [
'url' => '/s/{token}/authenticate/{redirect}',
'verb' => 'POST',
],
w(['name' => 'Public#showShare', 'url' => '/s/{token}/{path}', 'verb' => 'GET'], 'path'),
// Public album share
['name' => 'PublicAlbum#showShare', 'url' => '/a/{token}', 'verb' => 'GET'],

View File

@ -15,12 +15,15 @@ class FoldersController extends GenericApiController
{
/**
* @NoAdminRequired
*
* @PublicPage
*/
public function sub(string $folder): Http\Response
{
return Util::guardEx(function () use ($folder) {
try {
$node = Util::getUserFolder()->get($folder);
$rootNode = $this->fs->getShareNode() ?? Util::getUserFolder();
$node = $rootNode->get($folder);
} catch (\OCP\Files\NotFoundException) {
throw Exceptions::NotFound('Folder not found');
}
@ -60,7 +63,6 @@ class FoldersController extends GenericApiController
return [
'fileid' => $node->getId(),
'name' => $node->getName(),
'path' => $node->getPath(),
'previews' => $this->tq->getRootPreviews($root),
];
}, $folders);

View File

@ -84,7 +84,16 @@ class FsManager
throw new \Exception('Share is not a folder');
}
$root->addFolder($share);
if ($path = $this->getRequestFolder()) {
try {
$node = $share->get(Util::sanitizePath($path));
} catch (\OCP\Files\NotFoundException $e) {
throw new \Exception("Folder not found: {$e->getMessage()}");
}
$root->addFolder($node);
} else {
$root->addFolder($share);
}
return $root;
}

View File

@ -580,7 +580,7 @@ export default defineComponent({
}
// Folder
if (this.routeIsFolders) {
if (this.routeIsFolders || this.routeIsFolderShare) {
const path = utils.getFolderRoutePath(this.config.folders_path);
set(DaysFilterType.FOLDER, path);
if (this.$route.query.recursive) {

View File

@ -58,18 +58,17 @@ export default defineComponent({
computed: {
/** Open folder */
target() {
const path = this.data.path
.split('/')
.filter((x) => x)
.slice(2) as string[];
// Remove base path if present
const basePath = this.config.folders_path.split('/').filter((x) => x);
if (path.length >= basePath.length && path.slice(0, basePath.length).every((x, i) => x === basePath[i])) {
path.splice(0, basePath.length);
let currentPath: string[] | string = this.$route.params.path || [];
if (typeof currentPath === 'string') {
currentPath = currentPath.split('/');
}
return { name: 'folders', params: { path } };
return {
name: this.$route.name,
params: {
path: [...currentPath, this.data.name],
},
};
},
},
@ -89,12 +88,6 @@ export default defineComponent({
// Reset state
this.error = false;
// Check if valid path present
if (!this.data.path) {
this.error = true;
return;
}
// Get preview infos
const previews = this.data.previews;
if (previews) {

View File

@ -35,7 +35,7 @@ export default defineComponent({
},
currentmatter(): Component | null {
if (this.routeIsFolders) {
if (this.routeIsFolders || this.routeIsFolderShare) {
return FolderDynamicTopMatter;
} else if (this.routeIsPlaces) {
return PlacesDynamicTopMatterVue;
@ -53,8 +53,8 @@ export default defineComponent({
return this.$route.params.name || '';
}
// Show share name for public shares
if (this.routeIsPublic) {
// Show share name for public shares, except for folder share, because the name is already present in the breadcrumbs
if (this.routeIsPublic && !this.routeIsFolderShare) {
return PublicShareHeader.title;
}

View File

@ -1,16 +1,17 @@
<template>
<div class="top-matter">
<NcBreadcrumbs>
<NcBreadcrumb title="Home" :to="{ name: 'folders' }">
<template #icon>
<HomeIcon :size="20" />
<NcBreadcrumb :title="rootFolderName" :to="{ name: $route.name }">
<template v-if="routeIsPublic" #icon>
<ShareIcon :size="20" />
<span class="share-name">{{ rootFolderName }}</span>
</template>
</NcBreadcrumb>
<NcBreadcrumb
v-for="folder in list"
:key="folder.idx"
:title="folder.text"
:to="{ name: 'folders', params: { path: folder.path } }"
:to="{ name: $route.name, params: { path: folder.path } }"
/>
</NcBreadcrumbs>
@ -23,7 +24,12 @@
<TimelineIcon v-else :size="20" />
</template>
</NcActionButton>
<NcActionButton :aria-label="t('memories', 'Share folder')" @click="share()" close-after-click>
<NcActionButton
v-if="!routeIsPublic"
:aria-label="t('memories', 'Share folder')"
@click="share()"
close-after-click
>
{{ t('memories', 'Share folder') }}
<template #icon> <ShareIcon :size="20" /> </template>
</NcActionButton>
@ -42,8 +48,8 @@ import NcActions from '@nextcloud/vue/dist/Components/NcActions';
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton';
import * as utils from '../../services/utils';
import * as PublicShareHeader from './PublicShareHeader';
import HomeIcon from 'vue-material-design-icons/Home.vue';
import ShareIcon from 'vue-material-design-icons/ShareVariant.vue';
import TimelineIcon from 'vue-material-design-icons/ImageMultiple.vue';
import FoldersIcon from 'vue-material-design-icons/FolderMultiple.vue';
@ -56,7 +62,6 @@ export default defineComponent({
NcBreadcrumb,
NcActions,
NcActionButton,
HomeIcon,
ShareIcon,
TimelineIcon,
FoldersIcon,
@ -86,6 +91,10 @@ export default defineComponent({
recursive(): boolean {
return !!this.$route.query.recursive;
},
rootFolderName(): string {
return this.routeIsPublic ? PublicShareHeader.title : 'Home';
},
},
methods: {
@ -110,6 +119,9 @@ export default defineComponent({
.breadcrumb {
min-width: 0;
height: unset;
.share-name {
margin-left: 1em;
}
}
}
</style>

View File

@ -45,6 +45,7 @@ export default defineComponent({
currentmatter() {
switch (this.$route.name) {
case _m.routes.Folders.name:
case _m.routes.FolderShare.name:
return FolderTopMatter;
case _m.routes.Albums.name:
return AlbumTopMatter;

View File

@ -110,7 +110,7 @@ export const routes: { [key in RouteId]: RouteConfig } = {
},
FolderShare: {
path: '/s/:token',
path: '/s/:token/:path*',
component: Timeline,
name: 'folder-share',
props: (route: Route) => ({ rootTitle: t('memories', 'Shared Folder') }),

View File

@ -156,8 +156,6 @@ export interface IExif {
}
export interface IFolder extends IPhoto {
/** Path to folder */
path: string;
/** Photos for preview images */
previews?: IPhoto[];
/** Name of folder */