mirror of https://github.com/nextcloud/bookmarks
Projects: Add bookmarks folders
remove bookmark picker from collections.js for now as we don't have a picker, yet. Signed-off-by: Marcel Klehr <mklehr@gmx.net>
This commit is contained in:
parent
ddeb5fc953
commit
74fb4510f6
|
@ -11,6 +11,7 @@ namespace OCA\Bookmarks\AppInfo;
|
|||
use Closure;
|
||||
use OC\EventDispatcher\SymfonyAdapter;
|
||||
use OCA\Bookmarks\Activity\ActivityPublisher;
|
||||
use OCA\Bookmarks\Collaboration\Resources\FolderResourceProvider;
|
||||
use OCA\Bookmarks\Collaboration\Resources\ResourceProvider;
|
||||
use OCA\Bookmarks\Dashboard\Frequent;
|
||||
use OCA\Bookmarks\Dashboard\Recent;
|
||||
|
@ -95,6 +96,7 @@ class Application extends App implements IBootstrap {
|
|||
|
||||
protected function registerCollaborationResources(IProviderManager $resourceManager, SymfonyAdapter $symfonyAdapter): void {
|
||||
$resourceManager->registerResourceProvider(ResourceProvider::class);
|
||||
$resourceManager->registerResourceProvider(FolderResourceProvider::class);
|
||||
|
||||
$symfonyAdapter->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', static function () {
|
||||
Util::addScript('bookmarks', 'bookmarks-collections');
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
/*
|
||||
* Copyright (c) 2022. The Nextcloud Bookmarks contributors.
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or later. See the COPYING file.
|
||||
*/
|
||||
|
||||
namespace OCA\Bookmarks\Collaboration\Resources;
|
||||
|
||||
use OCA\Bookmarks\Db\Folder;
|
||||
use OCA\Bookmarks\Db\FolderMapper;
|
||||
use OCA\Bookmarks\Service\Authorizer;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\Collaboration\Resources\IProvider;
|
||||
use OCP\Collaboration\Resources\IResource;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
|
||||
class FolderResourceProvider implements IProvider {
|
||||
public const RESOURCE_TYPE = 'bookmarks-folder';
|
||||
/**
|
||||
* @var IURLGenerator
|
||||
*/
|
||||
private $url;
|
||||
/**
|
||||
* @var Authorizer
|
||||
*/
|
||||
private $authorizer;
|
||||
/**
|
||||
* @var FolderMapper
|
||||
*/
|
||||
private $folderMapper;
|
||||
|
||||
public function __construct(IURLGenerator $url, Authorizer $authorizer, FolderMapper $folderMapper) {
|
||||
$this->url = $url;
|
||||
$this->authorizer = $authorizer;
|
||||
$this->folderMapper = $folderMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getType(): string {
|
||||
return self::RESOURCE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getResourceRichObject(IResource $resource): array {
|
||||
$folder = $this->getFolder($resource);
|
||||
$favicon = $this->url->imagePath('bookmarks', 'bookmarks-black.svg');
|
||||
$resourceUrl = $this->url->linkToRouteAbsolute('bookmarks.web_view.indexfolder', ['folder' => $folder->getId()]);
|
||||
|
||||
return [
|
||||
'type' => self::RESOURCE_TYPE,
|
||||
'id' => $resource->getId(),
|
||||
'name' => $folder->getTitle(),
|
||||
'link' => $resourceUrl,
|
||||
'iconUrl' => $favicon,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function canAccessResource(IResource $resource, ?IUser $user): bool {
|
||||
if ($resource->getType() !== self::RESOURCE_TYPE || !($user instanceof IUser)) {
|
||||
return false;
|
||||
}
|
||||
$folder = $this->getFolder($resource);
|
||||
if ($folder === null) {
|
||||
return false;
|
||||
}
|
||||
if ($folder->getUserId() === $user->getUID()) {
|
||||
return true;
|
||||
}
|
||||
$permissions = $this->authorizer->getUserPermissionsForFolder($user->getUID(), $folder->getId());
|
||||
return Authorizer::hasPermission(Authorizer::PERM_READ, $permissions);
|
||||
}
|
||||
|
||||
private function getFolder(IResource $resource) : ?Folder {
|
||||
try {
|
||||
return $this->folderMapper->find((int) $resource->getId());
|
||||
} catch (MultipleObjectsReturnedException|DoesNotExistException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -59,11 +59,11 @@ class FolderMapper extends QBMapper {
|
|||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return Entity
|
||||
* @return Folder
|
||||
* @throws DoesNotExistException if not found
|
||||
* @throws MultipleObjectsReturnedException if more than one result
|
||||
*/
|
||||
public function find(int $id): Entity {
|
||||
public function find(int $id): Folder {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb
|
||||
->select('*')
|
||||
|
|
|
@ -6,70 +6,46 @@
|
|||
|
||||
import Vue from 'vue'
|
||||
import FolderPickerDialog from './components/FolderPickerDialog'
|
||||
import { Store } from 'vuex'
|
||||
import deepClone from 'clone-deep'
|
||||
import store, { actions } from './store'
|
||||
import AppGlobal from './mixins/AppGlobal'
|
||||
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
|
||||
|
||||
// eslint-disable-next-line no-unexpected-multiline
|
||||
(function(OCP, OC) {
|
||||
// eslint-disable-next-line
|
||||
__webpack_nonce__ = btoa(OC.requestToken)
|
||||
// eslint-disable-next-line
|
||||
__webpack_public_path__ = OC.linkTo('bookmarks', 'js/')
|
||||
|
||||
// eslint-disable-next-line
|
||||
__webpack_nonce__ = btoa(OC.requestToken)
|
||||
// eslint-disable-next-line
|
||||
__webpack_public_path__ = OC.linkTo('bookmarks', 'js/')
|
||||
Vue.mixin(AppGlobal)
|
||||
Vue.directive('tooltip', Tooltip)
|
||||
|
||||
Vue.prototype.t = t
|
||||
Vue.prototype.n = n
|
||||
Vue.prototype.OC = OC
|
||||
|
||||
OCP.Collaboration.registerType('bookmarks', {
|
||||
action: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const container = document.createElement('div')
|
||||
container.id = 'bookmarks-bookmark-select'
|
||||
const body = document.getElementById('body-user')
|
||||
body.appendChild(container)
|
||||
const ComponentVM = new Vue({
|
||||
render: h => h(FolderPickerDialog),
|
||||
})
|
||||
ComponentVM.$mount(container)
|
||||
ComponentVM.$root.$on('close', () => {
|
||||
ComponentVM.$el.remove()
|
||||
ComponentVM.$destroy()
|
||||
reject(new Error('User cancelled resource selection'))
|
||||
})
|
||||
ComponentVM.$root.$on('select', (id) => {
|
||||
resolve(id)
|
||||
ComponentVM.$el.remove()
|
||||
ComponentVM.$destroy()
|
||||
})
|
||||
OCP.Collaboration.registerType('bookmarks-folder', {
|
||||
action: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const container = document.createElement('div')
|
||||
container.id = 'bookmarks-bookmark-folder-select'
|
||||
const body = document.getElementById('body-user')
|
||||
body.appendChild(container)
|
||||
const ComponentVM = new Vue({
|
||||
render: h => h(FolderPickerDialog),
|
||||
store: new Store(deepClone(store)),
|
||||
})
|
||||
},
|
||||
typeString: t('bookmarks', 'Link to a bookmark'),
|
||||
typeIconClass: 'icon-favorite',
|
||||
})
|
||||
|
||||
OCP.Collaboration.registerType('bookmarks::folder', {
|
||||
action: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const container = document.createElement('div')
|
||||
container.id = 'bookmarks-bookmark-folder-select'
|
||||
const body = document.getElementById('body-user')
|
||||
body.appendChild(container)
|
||||
const ComponentVM = new Vue({
|
||||
render: h => h(FolderPickerDialog),
|
||||
})
|
||||
ComponentVM.$mount(container)
|
||||
ComponentVM.$root.$on('close', () => {
|
||||
ComponentVM.$el.remove()
|
||||
ComponentVM.$destroy()
|
||||
reject(new Error('User cancelled resource selection'))
|
||||
})
|
||||
ComponentVM.$root.$on('select', (id) => {
|
||||
resolve(id)
|
||||
ComponentVM.$el.remove()
|
||||
ComponentVM.$destroy()
|
||||
})
|
||||
ComponentVM.$store.dispatch(actions.LOAD_FOLDERS, true)
|
||||
ComponentVM.$mount(container)
|
||||
window.bookmarksPicker = ComponentVM
|
||||
ComponentVM.$root.$on('close', () => {
|
||||
ComponentVM.$el.remove()
|
||||
ComponentVM.$destroy()
|
||||
reject(new Error('User cancelled resource selection'))
|
||||
})
|
||||
},
|
||||
typeString: t('bookmarks', 'Link to a bookmark folder'),
|
||||
typeIconClass: 'icon-favorite',
|
||||
})
|
||||
})(window.OCP, window.OC)
|
||||
ComponentVM.$root.$on('select', (id) => {
|
||||
resolve(id)
|
||||
ComponentVM.$el.remove()
|
||||
ComponentVM.$destroy()
|
||||
})
|
||||
})
|
||||
},
|
||||
typeString: t('bookmarks', 'Link to a bookmark folder'),
|
||||
typeIconClass: 'icon-favorite',
|
||||
})
|
||||
|
|
|
@ -105,12 +105,7 @@ export default {
|
|||
|
||||
.currentfolder h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.currentfolder h2 .material-design-icon {
|
||||
position: relative;
|
||||
top: 5px;
|
||||
margin: 0 15px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.treefolder__title .material-design-icon {
|
||||
|
|
|
@ -39,11 +39,12 @@ export default {
|
|||
created() {},
|
||||
methods: {
|
||||
onSelect(folderId) {
|
||||
this.$root.$emit('select', folderId)
|
||||
this.$emit('input', folderId)
|
||||
this.$emit('select', folderId)
|
||||
this.$emit('close')
|
||||
},
|
||||
onClose() {
|
||||
this.$root.$emit('close')
|
||||
this.$emit('close')
|
||||
},
|
||||
},
|
||||
|
|
|
@ -95,7 +95,8 @@
|
|||
<a class="button" :href="archivedFile" target="_blank"><span class="icon-files-dark" /> {{ t('bookmarks', 'Open file location') }}</a>
|
||||
</div>
|
||||
</AppSidebarTab>
|
||||
<AppSidebarTab id="bookmark-projects"
|
||||
<AppSidebarTab v-if="!isPublic"
|
||||
id="bookmark-projects"
|
||||
:name="t('bookmarks', 'Projects')"
|
||||
icon="icon-projects"
|
||||
:order="1">
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
:title="folder.title"
|
||||
:active.sync="activeTab"
|
||||
@close="onClose">
|
||||
<AppSidebarTab id="folder-details" :name="t('bookmarks', 'Details')" icon="icon-info">
|
||||
<AppSidebarTab id="folder-details"
|
||||
:name="t('bookmarks', 'Details')"
|
||||
icon="icon-info"
|
||||
:order="0">
|
||||
<h3>{{ t('bookmarks', 'Owner') }}</h3>
|
||||
<UserBubble :user="folder.userId" :display-name="folder.userId" />
|
||||
<h3>{{ t('bookmarks', 'Bookmarks') }}</h3>
|
||||
|
@ -20,7 +23,8 @@
|
|||
<AppSidebarTab v-if="isSharable"
|
||||
id="folder-sharing"
|
||||
:name="t('bookmarks', 'Sharing')"
|
||||
icon="icon-shared">
|
||||
icon="icon-shared"
|
||||
:order="1">
|
||||
<div class="participant-select">
|
||||
<figure :class="{'icon-user': true, 'share__avatar': true }" />
|
||||
<Multiselect v-model="participant"
|
||||
|
@ -108,6 +112,16 @@
|
|||
</div>
|
||||
</div>
|
||||
</AppSidebarTab>
|
||||
<AppSidebarTab v-if="!isPublic"
|
||||
id="bookmark-projects"
|
||||
:name="t('bookmarks', 'Projects')"
|
||||
icon="icon-projects"
|
||||
:order="2">
|
||||
<CollectionList v-if="folder"
|
||||
:id="''+folder.id"
|
||||
:name="folder.title"
|
||||
type="bookmarks-folder" />
|
||||
</AppSidebarTab>
|
||||
</AppSidebar>
|
||||
</template>
|
||||
<script>
|
||||
|
@ -128,10 +142,11 @@ import { actions, mutations } from '../store/'
|
|||
import EyeIcon from 'vue-material-design-icons/Eye'
|
||||
import PencilIcon from 'vue-material-design-icons/Pencil'
|
||||
import ShareAllIcon from 'vue-material-design-icons/ShareAll'
|
||||
import { CollectionList } from 'nextcloud-vue-collections'
|
||||
|
||||
export default {
|
||||
name: 'SidebarFolder',
|
||||
components: { AppSidebar, AppSidebarTab, Avatar, Multiselect, ActionButton, ActionCheckbox, Actions, UserBubble, ActionSeparator, EyeIcon, PencilIcon, ShareAllIcon },
|
||||
components: { AppSidebar, AppSidebarTab, Avatar, Multiselect, ActionButton, ActionCheckbox, Actions, UserBubble, ActionSeparator, EyeIcon, PencilIcon, ShareAllIcon, CollectionList },
|
||||
data() {
|
||||
return {
|
||||
participantSearchResults: [],
|
||||
|
|
Loading…
Reference in New Issue