From 6130f1a78ea4f7fba3e3690528f2b53a0d9f5b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Thu, 1 Sep 2022 20:09:33 +0200 Subject: [PATCH] Implement file reference wiget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- .../composer/composer/autoload_classmap.php | 1 + .../composer/composer/autoload_static.php | 1 + apps/files/lib/AppInfo/Application.php | 3 + .../Listener/RenderReferenceEventListener.php | 39 ++++ apps/files/src/reference-files.js | 58 ++++++ .../src/views/FileReferencePickerElement.vue | 113 +++++++++++ apps/files/src/views/ReferenceFileWidget.vue | 182 ++++++++++++++++++ .../Reference/File/FileReferenceProvider.php | 42 +++- lib/public/RichObjectStrings/Definitions.php | 6 + webpack.modules.js | 1 + 10 files changed, 437 insertions(+), 9 deletions(-) create mode 100644 apps/files/lib/Listener/RenderReferenceEventListener.php create mode 100644 apps/files/src/reference-files.js create mode 100644 apps/files/src/views/FileReferencePickerElement.vue create mode 100644 apps/files/src/views/ReferenceFileWidget.vue diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index ef3480081e0..29ad9921eae 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -50,6 +50,7 @@ return array( 'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php', 'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => $baseDir . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files\\Listener\\RenderReferenceEventListener' => $baseDir . '/../lib/Listener/RenderReferenceEventListener.php', 'OCA\\Files\\Migration\\Version11301Date20191205150729' => $baseDir . '/../lib/Migration/Version11301Date20191205150729.php', 'OCA\\Files\\Migration\\Version12101Date20221011153334' => $baseDir . '/../lib/Migration/Version12101Date20221011153334.php', 'OCA\\Files\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index 4f7872e39df..5ed4124cbde 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -65,6 +65,7 @@ class ComposerStaticInitFiles 'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php', 'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => __DIR__ . '/..' . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files\\Listener\\RenderReferenceEventListener' => __DIR__ . '/..' . '/../lib/Listener/RenderReferenceEventListener.php', 'OCA\\Files\\Migration\\Version11301Date20191205150729' => __DIR__ . '/..' . '/../lib/Migration/Version11301Date20191205150729.php', 'OCA\\Files\\Migration\\Version12101Date20221011153334' => __DIR__ . '/..' . '/../lib/Migration/Version12101Date20221011153334.php', 'OCA\\Files\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php', diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index 01fe46bb877..e3152c77abc 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -44,6 +44,7 @@ use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadSidebar; use OCA\Files\Listener\LegacyLoadAdditionalScriptsAdapter; use OCA\Files\Listener\LoadSidebarListener; +use OCA\Files\Listener\RenderReferenceEventListener; use OCA\Files\Notification\Notifier; use OCA\Files\Search\FilesSearchProvider; use OCA\Files\Service\TagService; @@ -53,6 +54,7 @@ use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\Collaboration\Resources\IProviderManager; use OCP\IConfig; use OCP\IL10N; @@ -118,6 +120,7 @@ class Application extends App implements IBootstrap { $context->registerEventListener(LoadAdditionalScriptsEvent::class, LegacyLoadAdditionalScriptsAdapter::class); $context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class); + $context->registerEventListener(RenderReferenceEvent::class, RenderReferenceEventListener::class); $context->registerSearchProvider(FilesSearchProvider::class); diff --git a/apps/files/lib/Listener/RenderReferenceEventListener.php b/apps/files/lib/Listener/RenderReferenceEventListener.php new file mode 100644 index 00000000000..121ff745065 --- /dev/null +++ b/apps/files/lib/Listener/RenderReferenceEventListener.php @@ -0,0 +1,39 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCA\Files\Listener; + +use OCP\Collaboration\Reference\RenderReferenceEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; + +class RenderReferenceEventListener implements IEventListener { + public function handle(Event $event): void { + if (!$event instanceof RenderReferenceEvent) { + return; + } + + \OCP\Util::addScript('files', 'reference-files'); + } +} diff --git a/apps/files/src/reference-files.js b/apps/files/src/reference-files.js new file mode 100644 index 00000000000..db563200cd0 --- /dev/null +++ b/apps/files/src/reference-files.js @@ -0,0 +1,58 @@ +/** + * @copyright Copyright (c) 2022 Julius Härtl + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import Vue from 'vue' +import { translate as t } from '@nextcloud/l10n' + +import { registerWidget, registerCustomPickerElement, NcCustomPickerRenderResult } from '@nextcloud/vue/dist/Components/NcRichText.js' + +import FileWidget from './views/ReferenceFileWidget.vue' +import FileReferencePickerElement from './views/FileReferencePickerElement.vue' + +Vue.mixin({ + methods: { + t, + }, +}) + +registerWidget('file', (el, { richObjectType, richObject, accessible }) => { + const Widget = Vue.extend(FileWidget) + new Widget({ + propsData: { + richObjectType, + richObject, + accessible, + }, + }).$mount(el) +}) + +registerCustomPickerElement('files', (el, { providerId, accessible }) => { + const Element = Vue.extend(FileReferencePickerElement) + const vueElement = new Element({ + propsData: { + providerId, + accessible, + }, + }).$mount(el) + return new NcCustomPickerRenderResult(vueElement.$el, vueElement) +}, (el, renderResult) => { + renderResult.object.$destroy() +}) diff --git a/apps/files/src/views/FileReferencePickerElement.vue b/apps/files/src/views/FileReferencePickerElement.vue new file mode 100644 index 00000000000..543dba3350d --- /dev/null +++ b/apps/files/src/views/FileReferencePickerElement.vue @@ -0,0 +1,113 @@ + + + + + + + diff --git a/apps/files/src/views/ReferenceFileWidget.vue b/apps/files/src/views/ReferenceFileWidget.vue new file mode 100644 index 00000000000..f0ac7007312 --- /dev/null +++ b/apps/files/src/views/ReferenceFileWidget.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/lib/private/Collaboration/Reference/File/FileReferenceProvider.php b/lib/private/Collaboration/Reference/File/FileReferenceProvider.php index 95e49cdf860..d423a830495 100644 --- a/lib/private/Collaboration/Reference/File/FileReferenceProvider.php +++ b/lib/private/Collaboration/Reference/File/FileReferenceProvider.php @@ -25,8 +25,8 @@ declare(strict_types=1); namespace OC\Collaboration\Reference\File; use OC\User\NoUserException; +use OCP\Collaboration\Reference\ADiscoverableReferenceProvider; use OCP\Collaboration\Reference\IReference; -use OCP\Collaboration\Reference\IReferenceProvider; use OCP\Collaboration\Reference\Reference; use OCP\Files\IMimeTypeDetector; use OCP\Files\InvalidPathException; @@ -34,27 +34,34 @@ use OCP\Files\IRootFolder; use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\IL10N; use OCP\IPreview; use OCP\IURLGenerator; use OCP\IUserSession; +use OCP\L10N\IFactory; -class FileReferenceProvider implements IReferenceProvider { +class FileReferenceProvider extends ADiscoverableReferenceProvider { private IURLGenerator $urlGenerator; private IRootFolder $rootFolder; private ?string $userId; private IPreview $previewManager; private IMimeTypeDetector $mimeTypeDetector; - - public function __construct(IURLGenerator $urlGenerator, - IRootFolder $rootFolder, - IUserSession $userSession, - IMimeTypeDetector $mimeTypeDetector, - IPreview $previewManager) { + private IL10N $l10n; + + public function __construct( + IURLGenerator $urlGenerator, + IRootFolder $rootFolder, + IUserSession $userSession, + IMimeTypeDetector $mimeTypeDetector, + IPreview $previewManager, + IFactory $l10n + ) { $this->urlGenerator = $urlGenerator; $this->rootFolder = $rootFolder; $this->userId = $userSession->getUser() ? $userSession->getUser()->getUID() : null; $this->previewManager = $previewManager; $this->mimeTypeDetector = $mimeTypeDetector; + $this->l10n = $l10n->get('files'); } public function matchReference(string $referenceText): bool { @@ -145,9 +152,10 @@ class FileReferenceProvider implements IReferenceProvider { 'id' => $file->getId(), 'name' => $file->getName(), 'size' => $file->getSize(), - 'path' => $file->getPath(), + 'path' => $userFolder->getRelativePath($file->getPath()), 'link' => $reference->getUrl(), 'mimetype' => $file->getMimetype(), + 'mtime' => $file->getMTime(), 'preview-available' => $this->previewManager->isAvailable($file) ]); } catch (InvalidPathException|NotFoundException|NotPermittedException|NoUserException $e) { @@ -162,4 +170,20 @@ class FileReferenceProvider implements IReferenceProvider { public function getCacheKey(string $referenceId): ?string { return $this->userId ?? ''; } + + public function getId(): string { + return 'files'; + } + + public function getTitle(): string { + return $this->l10n->t('Files'); + } + + public function getOrder(): int { + return 0; + } + + public function getIconUrl(): string { + return $this->urlGenerator->imagePath('files', 'folder.svg'); + } } diff --git a/lib/public/RichObjectStrings/Definitions.php b/lib/public/RichObjectStrings/Definitions.php index 383d626c155..57da9f4eb30 100644 --- a/lib/public/RichObjectStrings/Definitions.php +++ b/lib/public/RichObjectStrings/Definitions.php @@ -347,6 +347,12 @@ class Definitions { 'description' => 'Whether or not a preview is available. If `no` the mimetype icon should be used', 'example' => 'yes', ], + 'mtime' => [ + 'since' => '25.0.0', + 'required' => false, + 'description' => 'The mtime of the file/folder as unix timestamp', + 'example' => '1661854213', + ], ], ], 'forms-form' => [ diff --git a/webpack.modules.js b/webpack.modules.js index 75524e2fa7f..8bc42d81e3a 100644 --- a/webpack.modules.js +++ b/webpack.modules.js @@ -52,6 +52,7 @@ module.exports = { sidebar: path.join(__dirname, 'apps/files/src', 'sidebar.js'), main: path.join(__dirname, 'apps/files/src', 'main.js'), 'personal-settings': path.join(__dirname, 'apps/files/src', 'main-personal-settings.js'), + 'reference-files': path.join(__dirname, 'apps/files/src', 'reference-files.js'), }, files_sharing: { additionalScripts: path.join(__dirname, 'apps/files_sharing/src', 'additionalScripts.js'),