diff options
author | Julien Veyssier <eneiluj@posteo.net> | 2020-12-14 14:36:10 +0100 |
---|---|---|
committer | Carl Schwan <carl@carlschwan.eu> | 2022-09-14 14:46:44 +0200 |
commit | 0915e4e1013c12a30372c713c2fe057acc119991 (patch) | |
tree | 0afc173bba929a3b62dc37c6340ee1cb83346f41 /src | |
parent | 3d439139d2b0a7561402bd9dd8a76e72ad3cbfc6 (diff) |
add dashboard widget, only handling internal 'Follow' subtypes for the moment
Signed-off-by: Julien Veyssier <eneiluj@posteo.net>
Diffstat (limited to 'src')
-rw-r--r-- | src/dashboard.js | 32 | ||||
-rw-r--r-- | src/views/Dashboard.vue | 200 |
2 files changed, 232 insertions, 0 deletions
diff --git a/src/dashboard.js b/src/dashboard.js new file mode 100644 index 00000000..48132a91 --- /dev/null +++ b/src/dashboard.js @@ -0,0 +1,32 @@ +/* jshint esversion: 6 */ + +/** + * Nextcloud - social + * + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Julien Veyssier <eneiluj@posteo.net> + * @copyright Julien Veyssier 2020 + */ + +import Vue from 'vue' +import { translate, translatePlural } from '@nextcloud/l10n' +import Dashboard from './views/Dashboard' + +Vue.prototype.t = translate +Vue.prototype.n = translatePlural +Vue.prototype.OC = window.OC +Vue.prototype.OCA = window.OCA + +document.addEventListener('DOMContentLoaded', function() { + + OCA.Dashboard.register('social_notifications', (el, { widget }) => { + const View = Vue.extend(Dashboard) + new View({ + propsData: { title: widget.title }, + }).$mount(el) + }) + +}) diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue new file mode 100644 index 00000000..bb5cbf8a --- /dev/null +++ b/src/views/Dashboard.vue @@ -0,0 +1,200 @@ +<template> + <DashboardWidget :items="items" + :show-more-url="showMoreUrl" + :show-more-text="title" + :loading="state === 'loading'"> + <template #empty-content> + <EmptyContent + v-if="emptyContentMessage" + :icon="emptyContentIcon"> + <template #desc> + {{ emptyContentMessage }} + <div v-if="state === 'error'" class="connect-button"> + <a class="button" :href="appUrl"> + {{ t('social', 'Go to Social app') }} + </a> + </div> + </template> + </EmptyContent> + </template> + </DashboardWidget> +</template> + +<script> +import axios from '@nextcloud/axios' +import { generateUrl } from '@nextcloud/router' +import { showError, showSuccess } from '@nextcloud/dialogs' +import moment from '@nextcloud/moment' +import { DashboardWidget } from '@nextcloud/vue-dashboard' +import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent' + +export default { + name: 'Dashboard', + + components: { + DashboardWidget, + EmptyContent, + }, + + props: { + title: { + type: String, + required: true, + }, + }, + + data() { + return { + notifications: [], + showMoreUrl: generateUrl('/apps/social/timeline/notifications'), + showMoreText: t('social', 'Social notifications'), + loop: null, + state: 'loading', + appUrl: generateUrl('/apps/social'), + } + }, + + computed: { + items() { + return this.notifications.map((n) => { + return { + id: n.id, + targetUrl: this.getNotificationTarget(n), + avatarUrl: this.getAvatarUrl(n), + avatarUsername: this.getActorName(n), + overlayIconUrl: this.getNotificationTypeImage(n), + mainText: this.getMainText(n), + subText: this.getSubline(n), + } + }) + }, + lastTimestamp() { + return this.notifications.length + ? this.notifications[0].publishedTime + : 0 + }, + emptyContentMessage() { + if (this.state === 'error') { + return t('social', 'Error getting Social notifications') + } else if (this.state === 'ok') { + return t('social', 'No Social notifications!') + } + return '' + }, + emptyContentIcon() { + if (this.state === 'error') { + return 'icon-close' + } else if (this.state === 'ok') { + return 'icon-checkmark' + } + return 'icon-checkmark' + }, + }, + + beforeMount() { + this.fetchNotifications() + this.loop = setInterval(() => this.fetchNotifications(), 10000) + }, + + methods: { + fetchNotifications() { + const req = { + params: { + limit: 10, + }, + } + const url = generateUrl('/apps/social/api/v1/stream/notifications') + // TODO check why 'since' param is in fact 'until' + /* if (this.lastDate) { + req.params.since = this.lastTimestamp, + } */ + axios.get(url, req).then((response) => { + if (response.data?.result) { + this.processNotifications(response.data.result) + this.state = 'ok' + } else { + this.state = 'error' + } + }).catch((error) => { + clearInterval(this.loop) + if (error.response?.status && error.response.status >= 400) { + showError(t('social', 'Failed to get Social notifications')) + this.state = 'error' + } else { + // there was an error in notif processing + console.error(error) + } + }) + }, + processNotifications(newNotifications) { + if (this.lastTimestamp !== 0) { + // just add those which are more recent than our most recent one + let i = 0 + while (i < newNotifications.length && this.lastTimestamp < newNotifications[i].publishedTime) { + i++ + } + if (i > 0) { + const toAdd = this.filter(newNotifications.slice(0, i)) + this.notifications = toAdd.concat(this.notifications) + } + } else { + // first time, we don't check the date + this.notifications = this.filter(newNotifications) + } + }, + filter(notifications) { + return notifications + // TODO check if we need to filter + /* return notifications.filter((n) => { + return (n.type === 'something' || n.subtype === 'somethingElse') + }) */ + }, + getMainText(n) { + if (n.subtype === 'Follow') { + return t('social', '{account} is following you', { account: this.getActorName(n) }) + } + }, + getAvatarUrl(n) { + return undefined + // TODO get external and internal avatars + /* return this.getActorAccountName(n) + ? generateUrl('???') + : undefined */ + }, + getActorName(n) { + return n.actor_info && n.actor_info.type === 'Person' && n.actor_info.preferredUsername + ? n.actor_info.preferredUsername + : '' + }, + getActorAccountName(n) { + return n.actor_info && n.actor_info.type === 'Person' && n.actor_info.account + ? n.actor_info.account + : '' + }, + getNotificationTarget(n) { + if (n.subtype === 'Follow') { + return generateUrl('/apps/social/@' + this.getActorAccountName(n) + '/') + } + return this.showMoreUrl + }, + getSubline(n) { + if (n.subtype === 'Follow') { + return this.getActorAccountName(n) + } + return '' + }, + getNotificationTypeImage(n) { + if (n.subtype === 'Follow') { + return generateUrl('/svg/social/add_user') + } + return '' + }, + }, +} +</script> + +<style scoped lang="scss"> +::v-deep .connect-button { + margin-top: 10px; +} +</style> |