From e7ab9f296cc2008b9608d29d83b3909f627e7629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 13 Jul 2020 09:02:29 +0200 Subject: [PATCH] Implement dashboard panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- img/newsletter.svg | 1 + lib/AppInfo/Application.php | 3 + lib/Dashboard/MailWidget.php | 112 +++++++++++++++++++++ lib/Listener/DashboardPanelListener.php | 48 +++++++++ package-lock.json | 104 +++++++++++++++++++ package.json | 1 + src/main-dashboard.js | 44 +++++++++ src/views/Dashboard.vue | 126 ++++++++++++++++++++++++ webpack.common.js | 1 + 9 files changed, 440 insertions(+) create mode 100644 img/newsletter.svg create mode 100644 lib/Dashboard/MailWidget.php create mode 100644 lib/Listener/DashboardPanelListener.php create mode 100644 src/main-dashboard.js create mode 100644 src/views/Dashboard.vue diff --git a/img/newsletter.svg b/img/newsletter.svg new file mode 100644 index 0000000000..7a8332c399 --- /dev/null +++ b/img/newsletter.svg @@ -0,0 +1 @@ +newsletter \ No newline at end of file diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index aeb49f13c4..10002803df 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -41,6 +41,7 @@ use OCA\Mail\Http\Middleware\ErrorMiddleware; use OCA\Mail\Http\Middleware\ProvisioningMiddleware; use OCA\Mail\Listener\AddressCollectionListener; +use OCA\Mail\Listener\DashboardPanelListener; use OCA\Mail\Listener\DeleteDraftListener; use OCA\Mail\Listener\DraftMailboxCreatorListener; use OCA\Mail\Listener\FlagRepliedMessageListener; @@ -59,6 +60,7 @@ use OCA\Mail\Service\UserPreferenceSevice; use OCP\AppFramework\App; use OCP\AppFramework\IAppContainer; +use OCP\Dashboard\RegisterWidgetEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\User\Events\UserDeletedEvent; use OCP\Util; @@ -115,5 +117,6 @@ private function registerEvents(IAppContainer $container): void { $dispatcher->addServiceListener(SaveDraftEvent::class, DraftMailboxCreatorListener::class); $dispatcher->addServiceListener(SynchronizationEvent::class, AccountSynchronizedThreadUpdaterListener::class); $dispatcher->addServiceListener(UserDeletedEvent::class, UserDeletedListener::class); + $dispatcher->addServiceListener(RegisterWidgetEvent::class, DashboardPanelListener::class); } } diff --git a/lib/Dashboard/MailWidget.php b/lib/Dashboard/MailWidget.php new file mode 100644 index 0000000000..1c2fc833af --- /dev/null +++ b/lib/Dashboard/MailWidget.php @@ -0,0 +1,112 @@ + + * + * @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\Mail\Dashboard; + +use OCA\Mail\AppInfo\Application; +use OCA\Mail\Service\AccountService; +use OCP\AppFramework\Services\IInitialState; +use OCP\Dashboard\IWidget; +use OCP\IL10N; +use OCP\IURLGenerator; +use OCP\Util; + +class MailWidget implements IWidget { + + /** @var IL10N */ + private $l10n; + + /** @var IURLGenerator */ + private $urlGenerator; + + /** @var AccountService */ + private $accountService; + + /** @var IInitialState */ + private $initialState; + + /** @var string|null */ + private $userId; + + public function __construct(IL10N $l10n, + IURLGenerator $urlGenerator, + AccountService $accountService, + IInitialState $initialState, + ?string $userId) { + $this->l10n = $l10n; + $this->urlGenerator = $urlGenerator; + $this->accountService = $accountService; + $this->initialState = $initialState; + $this->userId = $userId; + } + + /** + * @inheritDoc + */ + public function getId(): string { + return Application::APP_ID; + } + + /** + * @inheritDoc + */ + public function getTitle(): string { + return $this->l10n->t('Important mail'); + } + + /** + * @inheritDoc + */ + public function getOrder(): int { + return 4; + } + + /** + * @inheritDoc + */ + public function getIconClass(): string { + return 'icon-mail'; + } + + /** + * @inheritDoc + */ + public function getUrl(): ?string { + return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('mail.page.index')); + } + + /** + * @inheritDoc + */ + public function load(): void { + Util::addScript(Application::APP_ID, 'dashboard'); + + $this->initialState->provideInitialState( + 'mail-accounts', + $this->accountService->findByUserId($this->userId) + ); + } +} diff --git a/lib/Listener/DashboardPanelListener.php b/lib/Listener/DashboardPanelListener.php new file mode 100644 index 0000000000..e5917829b9 --- /dev/null +++ b/lib/Listener/DashboardPanelListener.php @@ -0,0 +1,48 @@ + + * + * @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\Mail\Listener; + +use OCA\Mail\Dashboard\MailWidget; +use OCP\Dashboard\RegisterWidgetEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; + +class DashboardPanelListener implements IEventListener { + + /** + * @inheritDoc + */ + public function handle(Event $event): void { + if (!($event instanceof RegisterWidgetEvent)) { + return; + } + + $event->registerWidget(MailWidget::class); + } +} diff --git a/package-lock.json b/package-lock.json index eefeecb4c6..ceae341797 100644 --- a/package-lock.json +++ b/package-lock.json @@ -953,6 +953,27 @@ "@babel/helper-plugin-utils": "^7.10.4" } }, + "@babel/polyfill": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.2.5.tgz", + "integrity": "sha512-8Y/t3MWThtMLYr0YNC/Q76tqN1w30+b0uQMeFUYauG2UGTR19zyUtFrAzT23zNtBxPp+LbE5E/nwV/q/r3y6ug==", + "requires": { + "core-js": "^2.5.7", + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, "@babel/preset-env": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.0.tgz", @@ -1657,6 +1678,44 @@ "vue2-datepicker": "^3.3.1" } }, + "@nextcloud/vue-dashboard": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@nextcloud/vue-dashboard/-/vue-dashboard-0.1.3.tgz", + "integrity": "sha512-7b02zkarX7b18IRQmZEW1NM+dvtcUih2M0+CZyuQfcvfyMQudOz+BdA/oD1p7PmdBds1IR8OvY1+CnpmgAzfQg==", + "requires": { + "@nextcloud/vue": "^2.3.0", + "core-js": "^3.6.4", + "vue": "^2.6.11" + }, + "dependencies": { + "@nextcloud/vue": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-2.3.0.tgz", + "integrity": "sha512-6uf7Hu4Obaet7BOs9H/Ng63xAYqks9CL7hsOOHGUzWFYrPPBxgt79iD9OOPpPfJuLQ3Nnuibh942X1QreCBRkw==", + "requires": { + "@nextcloud/auth": "^1.2.3", + "@nextcloud/axios": "^1.3.2", + "@nextcloud/dialogs": "^1.3.0", + "@nextcloud/event-bus": "^1.1.4", + "@nextcloud/l10n": "^1.2.3", + "@nextcloud/router": "^1.0.2", + "core-js": "^3.6.5", + "debounce": "1.2.0", + "emoji-mart-vue-fast": "^7.0.2", + "hammerjs": "^2.0.8", + "md5": "^2.2.1", + "regenerator-runtime": "^0.13.5", + "v-click-outside": "^3.0.1", + "v-tooltip": "^2.0.3", + "vue": "^2.6.11", + "vue-color": "^2.7.1", + "vue-multiselect": "^2.1.6", + "vue-visible": "^1.0.2", + "vue2-datepicker": "^3.4.1" + } + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", @@ -4695,6 +4754,31 @@ } } }, + "emoji-mart-vue-fast": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-mart-vue-fast/-/emoji-mart-vue-fast-7.0.3.tgz", + "integrity": "sha512-9BdX1QvWCOKEnmd20wcej7GaB/2/cesgodGJCCQirz1NtW3xctg1pWEYJHbAcjRHSHDzLDC+Y2xj9a2tO8T5hQ==", + "requires": { + "@babel/polyfill": "7.2.5", + "@babel/runtime": "7.3.4", + "vue-virtual-scroller": "^1.0.0-rc.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.4.tgz", + "integrity": "sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -10926,6 +11010,11 @@ "ajv-keywords": "^3.1.0" } }, + "scrollparent": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.0.1.tgz", + "integrity": "sha1-cV1bnMV3YPsivczDvvtb/gaxoxc=" + }, "scss-tokenizer": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", @@ -12676,6 +12765,11 @@ "resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.6.tgz", "integrity": "sha512-s7jmZPlm9FeueJg1RwJtnE9KNPtME/7C8uRWSfp9/yEN4M8XcS/d+bddoyVwVnvFyRh9msFo0HWeW0vTL8Qv+w==" }, + "vue-observe-visibility": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vue-observe-visibility/-/vue-observe-visibility-0.4.6.tgz", + "integrity": "sha512-xo0CEVdkjSjhJoDdLSvoZoQrw/H2BlzB5jrCBKGZNXN2zdZgMuZ9BKrxXDjNP2AxlcCoKc8OahI3F3r3JGLv2Q==" + }, "vue-on-click-outside": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/vue-on-click-outside/-/vue-on-click-outside-1.0.3.tgz", @@ -12790,6 +12884,16 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "vue-virtual-scroller": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/vue-virtual-scroller/-/vue-virtual-scroller-1.0.10.tgz", + "integrity": "sha512-Hn4qSBDhRY4XdngPioYy/ykDjrLX/NMm1fQXm/4UQQ/Xv1x8JbHGFZNftQowTcfICgN7yc31AKnUk1UGLJ2ndA==", + "requires": { + "scrollparent": "^2.0.1", + "vue-observe-visibility": "^0.4.4", + "vue-resize": "^0.4.5" + } + }, "vue-visible": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/vue-visible/-/vue-visible-1.0.2.tgz", diff --git a/package.json b/package.json index 2f4be7cb65..40fb7d7c27 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@nextcloud/moment": "^1.1.1", "@nextcloud/router": "^1.1.0", "@nextcloud/vue": "^1.5.0", + "@nextcloud/vue-dashboard": "^0.1.3", "@vue/babel-preset-app": "^4.4.6", "color-convert": "^2.0.1", "core-js": "^3.6.5", diff --git a/src/main-dashboard.js b/src/main-dashboard.js new file mode 100644 index 0000000000..9eb22157ba --- /dev/null +++ b/src/main-dashboard.js @@ -0,0 +1,44 @@ +/* + * @copyright Copyright (c) 2020 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 { getRequestToken } from '@nextcloud/auth' +import { generateFilePath } from '@nextcloud/router' + +import Nextcloud from './mixins/Nextcloud' +import Dashboard from './views/Dashboard' + +// eslint-disable-next-line camelcase +__webpack_nonce__ = btoa(getRequestToken()) +// eslint-disable-next-line camelcase +__webpack_public_path__ = generateFilePath('mail', '', 'js/') + +Vue.mixin(Nextcloud) + +document.addEventListener('DOMContentLoaded', function() { + const register = OCA?.Dashboard?.register || (() => {}) + + register('mail', (el) => { + const View = Vue.extend(Dashboard) + new View().$mount(el) + }) +}) diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue new file mode 100644 index 0000000000..90f714f75e --- /dev/null +++ b/src/views/Dashboard.vue @@ -0,0 +1,126 @@ + + + + + + + diff --git a/webpack.common.js b/webpack.common.js index e913702c7f..f3d0a0c5ea 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -20,6 +20,7 @@ if (process.env.BUNDLE_ANALYZER_TOKEN) { module.exports = { entry: { autoredirect: path.join(__dirname, 'src/autoredirect.js'), + dashboard: path.join(__dirname, 'src/main-dashboard.js'), mail: path.join(__dirname, 'src/main.js'), settings: path.join(__dirname, 'src/main-settings') },