diff options
author | Richard Steinmetz <richard@steinmetz.cloud> | 2023-08-17 15:09:30 +0200 |
---|---|---|
committer | Joas Schilling <coding@schilljs.com> | 2023-08-22 10:38:46 +0200 |
commit | 3fd18ce450c62719d12810732d0ef6ac083f8736 (patch) | |
tree | d782ac2e180b216c3d74fc7bbd49960795bb1943 /apps/user_status | |
parent | 2a435e8bd2567d8ca68976de4dec7bc3eea9a853 (diff) | |
download | nextcloud-server-3fd18ce450c62719d12810732d0ef6ac083f8736.tar.gz nextcloud-server-3fd18ce450c62719d12810732d0ef6ac083f8736.zip |
feat(dashboard): implement widget item api v2
This API enables the dashboard to render all widgets from the API data
alone without having apps to provide their own bundles. This saves a lot
of traffic and execution time as a lot less javascript has to be parsed
on the frontend.
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
Diffstat (limited to 'apps/user_status')
-rw-r--r-- | apps/user_status/lib/Dashboard/UserStatusWidget.php | 27 | ||||
-rw-r--r-- | apps/user_status/src/dashboard.js | 44 | ||||
-rw-r--r-- | apps/user_status/src/views/Dashboard.vue | 121 | ||||
-rw-r--r-- | apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php | 171 |
4 files changed, 16 insertions, 347 deletions
diff --git a/apps/user_status/lib/Dashboard/UserStatusWidget.php b/apps/user_status/lib/Dashboard/UserStatusWidget.php index 2e1de3cd6cf..89b9c05f805 100644 --- a/apps/user_status/lib/Dashboard/UserStatusWidget.php +++ b/apps/user_status/lib/Dashboard/UserStatusWidget.php @@ -6,6 +6,7 @@ declare(strict_types=1); * @copyright Copyright (c) 2020, Georg Ehrke * * @author Georg Ehrke <oc.list@georgehrke.com> + * @author Richard Steinmetz <richard@steinmetz.cloud> * * @license GNU AGPL version 3 or any later version * @@ -31,9 +32,11 @@ use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Services\IInitialState; use OCP\Dashboard\IAPIWidget; use OCP\Dashboard\IButtonWidget; +use OCP\Dashboard\IAPIWidgetV2; use OCP\Dashboard\IIconWidget; use OCP\Dashboard\IOptionWidget; use OCP\Dashboard\Model\WidgetItem; +use OCP\Dashboard\Model\WidgetItems; use OCP\Dashboard\Model\WidgetOptions; use OCP\IDateTimeFormatter; use OCP\IL10N; @@ -48,7 +51,7 @@ use OCP\Util; * * @package OCA\UserStatus */ -class UserStatusWidget implements IAPIWidget, IIconWidget, IOptionWidget { +class UserStatusWidget implements IAPIWidget, IAPIWidgetV2, IIconWidget, IOptionWidget { private IL10N $l10n; private IDateTimeFormatter $dateTimeFormatter; private IURLGenerator $urlGenerator; @@ -132,17 +135,6 @@ class UserStatusWidget implements IAPIWidget, IIconWidget, IOptionWidget { * @inheritDoc */ public function load(): void { - Util::addScript(Application::APP_ID, 'dashboard'); - - $currentUser = $this->userSession->getUser(); - if ($currentUser === null) { - $this->initialStateService->provideInitialState('dashboard_data', []); - return; - } - $currentUserId = $currentUser->getUID(); - - $widgetItemsData = $this->getWidgetData($currentUserId); - $this->initialStateService->provideInitialState('dashboard_data', $widgetItemsData); } private function getWidgetData(string $userId, ?string $since = null, int $limit = 7): array { @@ -201,6 +193,17 @@ class UserStatusWidget implements IAPIWidget, IIconWidget, IOptionWidget { }, $widgetItemsData); } + /** + * @inheritDoc + */ + public function getItemsV2(string $userId, ?string $since = null, int $limit = 7): WidgetItems { + $items = $this->getItems($userId, $since, $limit); + return new WidgetItems( + $items, + count($items) === 0 ? $this->l10n->t('No recent status changes') : '', + ); + } + public function getWidgetOptions(): WidgetOptions { return new WidgetOptions(true); } diff --git a/apps/user_status/src/dashboard.js b/apps/user_status/src/dashboard.js deleted file mode 100644 index 4554dcba1b0..00000000000 --- a/apps/user_status/src/dashboard.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.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 { translate, translatePlural } from '@nextcloud/l10n' -import Dashboard from './views/Dashboard.vue' - -// eslint-disable-next-line camelcase -__webpack_nonce__ = btoa(getRequestToken()) - -Vue.prototype.t = translate -Vue.prototype.n = translatePlural -Vue.prototype.OC = OC -Vue.prototype.OCA = OCA - -document.addEventListener('DOMContentLoaded', function() { - OCA.Dashboard.register('user_status', (el) => { - const View = Vue.extend(Dashboard) - new View({ - propsData: {}, - }).$mount(el) - }) - -}) diff --git a/apps/user_status/src/views/Dashboard.vue b/apps/user_status/src/views/Dashboard.vue deleted file mode 100644 index 1f9201cd118..00000000000 --- a/apps/user_status/src/views/Dashboard.vue +++ /dev/null @@ -1,121 +0,0 @@ -<!-- - - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com> - - @author Georg Ehrke <oc.list@georgehrke.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/>. - - - --> - -<template> - <NcDashboardWidget id="user-status_panel" - :items="items" - :loading="loading" - :empty-content-message="t('user_status', 'No recent status changes')"> - <template #default="{ item }"> - <NcDashboardWidgetItem :main-text="item.mainText" - :sub-text="item.subText"> - <template #avatar> - <NcAvatar class="item-avatar" - :size="44" - :user="item.avatarUsername" - :display-name="item.mainText" - :show-user-status="false" - :show-user-status-compact="false" /> - </template> - </NcDashboardWidgetItem> - </template> - <template #emptyContentIcon> - <div class="icon-user-status-dark" /> - </template> - </NcDashboardWidget> -</template> - -<script> -import { loadState } from '@nextcloud/initial-state' -import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js' -import NcDashboardWidget from '@nextcloud/vue/dist/Components/NcDashboardWidget.js' -import NcDashboardWidgetItem from '@nextcloud/vue/dist/Components/NcDashboardWidgetItem.js' -import moment from '@nextcloud/moment' - -export default { - name: 'Dashboard', - components: { - NcAvatar, - NcDashboardWidget, - NcDashboardWidgetItem, - }, - data() { - return { - statuses: [], - loading: true, - } - }, - computed: { - items() { - return this.statuses.map((item) => { - const icon = item.icon || '' - let message = item.message || '' - if (message === '') { - if (item.status === 'away') { - message = t('user_status', 'Away') - } - if (item.status === 'dnd') { - message = t('user_status', 'Do not disturb') - } - } - const status = item.icon !== '' ? `${icon} ${message}` : message - - let subText - if (item.icon === null && message === '' && item.timestamp === null) { - subText = '' - } else if (item.icon === null && message === '' && item.timestamp !== null) { - subText = moment(item.timestamp, 'X').fromNow() - } else if (item.timestamp !== null) { - subText = this.t('user_status', '{status}, {timestamp}', { - status, - timestamp: moment(item.timestamp, 'X').fromNow(), - }, null, { escape: false, sanitize: false }) - } else { - subText = status - } - - return { - mainText: item.displayName, - subText, - avatarUsername: item.userId, - } - }) - }, - }, - mounted() { - try { - this.statuses = loadState('user_status', 'dashboard_data') - this.loading = false - } catch (e) { - console.error(e) - } - }, -} -</script> - -<style lang="scss"> -.icon-user-status-dark { - width: 64px; - height: 64px; - background-size: 64px; - filter: var(--background-invert-if-dark); -} -</style> diff --git a/apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php b/apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php index 5481325510c..9e1c39f6858 100644 --- a/apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php +++ b/apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php @@ -7,6 +7,7 @@ declare(strict_types=1); * * @author Christoph Wurst <christoph@winzerhof-wurst.at> * @author Georg Ehrke <oc.list@georgehrke.com> + * @author Richard Steinmetz <richard@steinmetz.cloud> * * @license GNU AGPL version 3 or any later version * @@ -27,13 +28,11 @@ declare(strict_types=1); namespace OCA\UserStatus\Tests\Dashboard; use OCA\UserStatus\Dashboard\UserStatusWidget; -use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Services\IInitialState; use OCP\IDateTimeFormatter; use OCP\IL10N; use OCP\IURLGenerator; -use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; use Test\TestCase; @@ -101,172 +100,4 @@ class UserStatusWidgetTest extends TestCase { public function testGetUrl(): void { $this->assertNull($this->widget->getUrl()); } - - public function testLoadNoUserSession(): void { - $this->userSession->expects($this->once()) - ->method('getUser') - ->willReturn(null); - - $this->initialState->expects($this->once()) - ->method('provideInitialState') - ->with('dashboard_data', []); - - $this->service->expects($this->never()) - ->method('findAllRecentStatusChanges'); - - $this->widget->load(); - } - - public function testLoadWithCurrentUser(): void { - $user = $this->createMock(IUser::class); - $user->method('getUid')->willReturn('john.doe'); - $this->userSession->expects($this->once()) - ->method('getUser') - ->willReturn($user); - - $user1 = $this->createMock(IUser::class); - $user1->method('getDisplayName')->willReturn('User No. 1'); - - $this->userManager - ->method('get') - ->willReturnMap([ - ['user_1', $user1], - ['user_2', null], - ['user_3', null], - ['user_4', null], - ['user_5', null], - ['user_6', null], - ['user_7', null], - ]); - - $userStatuses = [ - UserStatus::fromParams([ - 'userId' => 'user_1', - 'status' => 'online', - 'customIcon' => '💻', - 'customMessage' => 'Working', - 'statusTimestamp' => 5000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_2', - 'status' => 'away', - 'customIcon' => '☕️', - 'customMessage' => 'Office Hangout', - 'statusTimestamp' => 6000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_3', - 'status' => 'dnd', - 'customIcon' => null, - 'customMessage' => null, - 'statusTimestamp' => 7000, - ]), - UserStatus::fromParams([ - 'userId' => 'john.doe', - 'status' => 'away', - 'customIcon' => '☕️', - 'customMessage' => 'Office Hangout', - 'statusTimestamp' => 90000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_4', - 'status' => 'dnd', - 'customIcon' => null, - 'customMessage' => null, - 'statusTimestamp' => 7000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_5', - 'status' => 'invisible', - 'customIcon' => '🏝', - 'customMessage' => 'On vacation', - 'statusTimestamp' => 7000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_6', - 'status' => 'offline', - 'customIcon' => null, - 'customMessage' => null, - 'statusTimestamp' => 7000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_7', - 'status' => 'invisible', - 'customIcon' => null, - 'customMessage' => null, - 'statusTimestamp' => 7000, - ]), - ]; - - $this->service->expects($this->once()) - ->method('findAllRecentStatusChanges') - ->with(8, 0) - ->willReturn($userStatuses); - - $this->initialState->expects($this->once()) - ->method('provideInitialState') - ->with('dashboard_data', $this->callback(function ($data): bool { - $this->assertEquals([ - [ - 'userId' => 'user_1', - 'displayName' => 'User No. 1', - 'status' => 'online', - 'icon' => '💻', - 'message' => 'Working', - 'timestamp' => 5000, - ], - [ - 'userId' => 'user_2', - 'displayName' => 'user_2', - 'status' => 'away', - 'icon' => '☕️', - 'message' => 'Office Hangout', - 'timestamp' => 6000, - ], - [ - 'userId' => 'user_3', - 'displayName' => 'user_3', - 'status' => 'dnd', - 'icon' => null, - 'message' => null, - 'timestamp' => 7000, - ], - [ - 'userId' => 'user_4', - 'displayName' => 'user_4', - 'status' => 'dnd', - 'icon' => null, - 'message' => null, - 'timestamp' => 7000, - ], - [ - 'userId' => 'user_5', - 'displayName' => 'user_5', - 'status' => 'offline', - 'icon' => '🏝', - 'message' => 'On vacation', - 'timestamp' => 7000, - ], - [ - 'userId' => 'user_6', - 'displayName' => 'user_6', - 'status' => 'offline', - 'icon' => null, - 'message' => null, - 'timestamp' => 7000, - ], - [ - 'userId' => 'user_7', - 'displayName' => 'user_7', - 'status' => 'offline', - 'icon' => null, - 'message' => null, - 'timestamp' => 7000, - ], - ], $data); - return true; - })); - - $this->widget->load(); - } } |