diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 9f5f6f571..87847d076 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -116,6 +116,7 @@ use OCA\Talk\Search\ConversationSearch; 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 @@ class Application extends App implements IBootstrap { $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 000000000..920942e69 --- /dev/null +++ b/lib/Search/UnifiedSearchFilterPlugin.php @@ -0,0 +1,53 @@ + + * + * @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\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 + */ +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 000000000..55c9dcb3d --- /dev/null +++ b/src/search.js @@ -0,0 +1,100 @@ +/* + * @copyright Copyright (c) 2024 Fon E. Noel NFEBE + * + * @author Vincent Petry + * + * @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 . + * + */ + +import Vue from 'vue' + +import { getRequestToken } from '@nextcloud/auth' +import { emit } from '@nextcloud/event-bus' +import { translate, translatePlural } from '@nextcloud/l10n' +import { generateFilePath, imagePath } from '@nextcloud/router' + +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: imagePath('spreed', '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 RoomSelector = () => import('./components/RoomSelector.vue') + const vm = new Vue({ + el: container, + render: h => h(RoomSelector, { + props: { + dialogTitle: t('spreed', 'Select conversation'), + isPlugin: true, + }, + }), + }) + + vm.$root.$on('close', () => { + vm.$el.remove() + vm.$destroy() + }) + vm.$root.$on('select', (conversation) => { + vm.$el.remove() + vm.$destroy() + + 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 da6e74015..4f5bf9bdd 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: {