From d599e159abd4fae8c333b16efce5387f214b6d59 Mon Sep 17 00:00:00 2001 From: fenn-cs <fenn25.fn@gmail.com> Date: Sat, 10 Feb 2024 22:55:34 +0100 Subject: [PATCH] Feat: Plug-in talk specific filters for unified search Signed-off-by: fenn-cs <fenn25.fn@gmail.com> --- lib/AppInfo/Application.php | 2 + lib/Search/UnifiedSearchFilterPlugin.php | 53 ++++++++++++ src/search.js | 103 +++++++++++++++++++++++ webpack.config.js | 1 + 4 files changed, 159 insertions(+) create mode 100644 lib/Search/UnifiedSearchFilterPlugin.php create mode 100644 src/search.js diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 9f5f6f571ea0..87847d0768df 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -116,6 +116,7 @@ use OCA\Talk\Search\CurrentMessageSearch; use OCA\Talk\Search\MessageSearch; use OCA\Talk\Search\UnifiedSearchCSSLoader; +use OCA\Talk\Search\UnifiedSearchFilterPlugin; use OCA\Talk\Settings\Personal; use OCA\Talk\Share\Listener as ShareListener; use OCA\Talk\Signaling\Listener as SignalingListener; @@ -175,6 +176,7 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(\OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent::class, UnifiedSearchCSSLoader::class); $context->registerEventListener(\OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent::class, DeckPluginLoader::class); $context->registerEventListener(\OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent::class, MapsPluginLoader::class); + $context->registerEventListener(\OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent::class, UnifiedSearchFilterPlugin::class); $context->registerEventListener(RegisterOperationsEvent::class, RegisterOperationsListener::class); $context->registerEventListener(BeforeTemplateRenderedEvent::class, PublicShareTemplateLoader::class); $context->registerEventListener(BeforeTemplateRenderedEvent::class, PublicShareAuthTemplateLoader::class); diff --git a/lib/Search/UnifiedSearchFilterPlugin.php b/lib/Search/UnifiedSearchFilterPlugin.php new file mode 100644 index 000000000000..920942e699c5 --- /dev/null +++ b/lib/Search/UnifiedSearchFilterPlugin.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2024 Fon E. Noel NFEBE <me@nfebe.com> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Talk\Search; + +use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\IRequest; +use OCP\Util; + +/** + * @template-implements IEventListener<Event> + */ +class UnifiedSearchFilterPlugin implements IEventListener { + + public function __construct( + private IRequest $request, + ) { + } + + public function handle(Event $event): void { + if (!($event instanceof BeforeTemplateRenderedEvent)) { + return; + } + + if (!$event->isLoggedIn()) { + return; + } + + Util::addScript('spreed', 'talk-search'); + } +} diff --git a/src/search.js b/src/search.js new file mode 100644 index 000000000000..87e8e3030802 --- /dev/null +++ b/src/search.js @@ -0,0 +1,103 @@ +/* + * @copyright Copyright (c) 2024 Fon E. Noel NFEBE <me@nfebe.com> + * + * @author Vincent Petry <me@nfebe.com> + * + * @license AGPL-3.0-or-later + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + +import Vue from 'vue' + +import { getRequestToken } from '@nextcloud/auth' +import { emit } from '@nextcloud/event-bus' +import { translate, translatePlural } from '@nextcloud/l10n' +import { generateFilePath } from '@nextcloud/router' + +import RoomSelector from './components/RoomSelector.vue' + +import { fetchConversation } from './services/conversationsService.js' + +import '@nextcloud/dialogs/style.css' + +(function(OC, OCP, t, n) { + + /** + * + */ + function init() { + if (!OCP.UnifiedSearch) { + return + } + console.debug('Initializing unified search plugin-filters from talk') + OCP.UnifiedSearch.registerFilterAction({ + id: 'talk-message', + label: t('spreed', 'In conversation'), + icon: '/apps/spreed/img/app.svg', + callback: () => { + const container = document.createElement('div') + container.id = 'spreed-unified-search-conversation-select' + const body = document.getElementById('body-user') + body.appendChild(container) + + const ComponentVM = Vue.extend(RoomSelector) + const vm = new ComponentVM({ + el: container, + propsData: { + dialogTitle: t('spreed', 'Select conversation'), + }, + }) + + vm.$root.$on('close', () => { + vm.$el.remove() + vm.$destroy() + }) + vm.$root.$on('select', (token) => { + vm.$el.remove() + vm.$destroy() + fetchConversation(token).then(response => { + const conversation = response.data.ocs.data + emit('nextcloud:unified-search:add-filter', { + id: 'talk-message', + payload: conversation, + filterUpdateText: t('spreed', 'Search in conversation: {conversation}', { conversation: conversation.displayName }), + filterParams: { conversation: conversation.token } + }) + }) + }) + }, + }) + } + + // CSP config for webpack dynamic chunk loading + // eslint-disable-next-line + __webpack_nonce__ = btoa(getRequestToken()) + + // Correct the root of the app for chunk loading + // OC.linkTo matches the apps folders + // OC.generateUrl ensure the index.php (or not) + // We do not want the index.php since we're loading files + // eslint-disable-next-line + __webpack_public_path__ = generateFilePath('spreed', '', 'js/') + + Vue.prototype.t = translate + Vue.prototype.n = translatePlural + Vue.prototype.OC = OC + Vue.prototype.OCP = OCP + + document.addEventListener('DOMContentLoaded', init) + +})(window.OC, window.OCP, t, n) diff --git a/webpack.config.js b/webpack.config.js index da6e74015903..4f5bf9bdd971 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -32,6 +32,7 @@ module.exports = mergeWithRules({ dashboard: path.join(__dirname, 'src', 'dashboard.js'), deck: path.join(__dirname, 'src', 'deck.js'), maps: path.join(__dirname, 'src', 'maps.js'), + search: path.join(__dirname, 'src', 'search.js'), }, output: {