diff options
author | Louis <6653109+artonge@users.noreply.github.com> | 2023-04-11 11:42:12 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-11 11:42:12 +0200 |
commit | 4d056fe998e227da2e3f486679e2f2d39cb1ce34 (patch) | |
tree | e92331081e9e7693aff1ec60a8184b992f365698 | |
parent | 29a3d2e07873e596289c2b93059845ce03112b44 (diff) | |
parent | 764bfcc3091ab38dc60546357ec3953bbc41b17f (diff) |
Merge pull request #1719 from nextcloud/artonge/fix/fixes
Tiny fixes all around
-rw-r--r-- | lib/AppInfo/Application.php | 2 | ||||
-rw-r--r-- | src/components/Composer/Composer.vue | 9 | ||||
-rw-r--r-- | src/components/ProfileInfo.vue | 9 | ||||
-rw-r--r-- | src/components/TimelineAvatar.vue | 7 | ||||
-rw-r--r-- | src/components/TimelineEntry.vue | 34 | ||||
-rw-r--r-- | src/components/TimelineList.vue | 2 | ||||
-rw-r--r-- | src/components/TimelinePost.vue | 7 | ||||
-rw-r--r-- | src/dashboard.js | 5 | ||||
-rw-r--r-- | src/main.js | 5 | ||||
-rw-r--r-- | src/services/notifications.js | 32 | ||||
-rw-r--r-- | src/views/Dashboard.vue | 69 | ||||
-rw-r--r-- | src/views/ProfilePageIntegration.vue | 12 |
12 files changed, 102 insertions, 91 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index b7fac6c7..7ef42a73 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -60,7 +60,7 @@ class Application extends App implements IBootstrap { $context->registerSearchProvider(UnifiedSearchProvider::class); $context->registerWellKnownHandler(WebfingerHandler::class); $context->registerEventListener(BeforeTemplateRenderedEvent::class, ProfileSectionListener::class); -// $context->registerDashboardWidget(SocialWidget::class); + $context->registerDashboardWidget(SocialWidget::class); } public function boot(IBootContext $context): void { diff --git a/src/components/Composer/Composer.vue b/src/components/Composer/Composer.vue index 0b43ce36..14b167df 100644 --- a/src/components/Composer/Composer.vue +++ b/src/components/Composer/Composer.vue @@ -169,13 +169,13 @@ export default { }, defaultVisibility: { type: String, - default: localStorage.getItem('social.lastPostType') || 'followers', + default: undefined, }, }, data() { return { statusContent: '', - visibility: this.defaultVisibility, + visibility: this.defaultVisibility || localStorage.getItem('social.lastPostType') || 'followers', loading: false, /** @type {Object<string, LocalAttachment>} */ attachments: {}, @@ -301,14 +301,14 @@ export default { * @param {import('../../types/Mastodon.js').Account} account */ prefillMessageWithMention(account) { - if (!this.statusIsEmpty) { + if (!this.statusIsEmpty || this.$refs.composerInput === undefined) { return } this.$refs.composerInput.innerHTML = ` <span class="mention" contenteditable="false"> <a href="${account.url}" target="_blank"> - <img src="${!account.acct.includes('@') ? generateUrl(`/avatar/${account.username}/32`) : generateUrl(`apps/social/api/v1/global/actor/avatar?id=${account.acct}`)}"/> + <img src="${account.avatar}"/> @${account.acct} </a> </span> ` @@ -413,6 +413,7 @@ export default { this.loading = false this.replyTo = null this.$refs.composerInput.innerText = '' + this.updateStatusContent() this.attachments = {} this.$store.dispatch('refreshTimeline') } diff --git a/src/components/ProfileInfo.vue b/src/components/ProfileInfo.vue index fecc1a6a..6ebdbead 100644 --- a/src/components/ProfileInfo.vue +++ b/src/components/ProfileInfo.vue @@ -27,7 +27,7 @@ :disable-tooltip="true" :size="128" /> <NcAvatar v-else - :url="avatarUrl" + :url="accountInfo.avatar" :disable-tooltip="true" :size="128" /> <h2>{{ displayName }}</h2> @@ -57,6 +57,9 @@ {{ t('social', 'Website') }}: <a :href="website.value">{{ website.value }}<OpenInNew :size="15" /></a> </p> + <!-- Hack to render note safely --> + <MessageContent v-if="accountInfo.note" class="user-profile__note" :item="{content: accountInfo.note, tag: [], mentions: []}" /> + <FollowButton class="user-profile__info" :account="accountInfo.acct" :uid="uid" /> <NcButton v-if="serverData.public" class="user-profile__info primary" @@ -158,6 +161,10 @@ export default { } + &__note { + text-align: start; + } + &__sections { display: flex; diff --git a/src/components/TimelineAvatar.vue b/src/components/TimelineAvatar.vue index cb04bdc4..11aeb658 100644 --- a/src/components/TimelineAvatar.vue +++ b/src/components/TimelineAvatar.vue @@ -43,11 +43,14 @@ export default { } </script> -<style scoped> +<style scoped lang='scss'> .post-avatar { - position: relative; padding: 5px 10px 10px 5px; height: 52px; width: 52px; + + .avatardiv { + position: static; + } } </style> diff --git a/src/components/TimelineEntry.vue b/src/components/TimelineEntry.vue index 1da0222d..2c641ebe 100644 --- a/src/components/TimelineEntry.vue +++ b/src/components/TimelineEntry.vue @@ -1,5 +1,5 @@ <template> - <div :class="['timeline-entry', hasHeader ? 'with-header' : '']"> + <li :class="['timeline-entry', hasHeader ? 'with-header' : '']"> <div v-if="isNotification" class="notification"> <Bell :size="22" /> <span class="notification-action"> @@ -30,15 +30,16 @@ :type="type" /> </div> </template> - </div> + </li> </template> <script> +import Bell from 'vue-material-design-icons/Bell.vue' +import { translate } from '@nextcloud/l10n' import TimelinePost from './TimelinePost.vue' import TimelineAvatar from './TimelineAvatar.vue' import UserEntry from './UserEntry.vue' -import Bell from 'vue-material-design-icons/Bell.vue' -import { translate } from '@nextcloud/l10n' +import { notificationSummary } from '../services/notifications.js' export default { name: 'TimelineEntry', @@ -102,30 +103,7 @@ export default { * @return {string} */ actionSummary() { - switch (this.notification.type) { - case 'mention': - return t('social', '{account} mentioned you', { account: this.notification.account.acct }) - case 'status': - return t('social', '{account} posted a status', { account: this.notification.account.acct }) - case 'reblog': - return t('social', '{account} boosted your post', { account: this.notification.account.acct }) - case 'follow': - return t('social', '{account} started to follow you', { account: this.notification.account.acct }) - case 'follow_request': - return t('social', '{account} requested to follow you', { account: this.notification.account.acct }) - case 'favourite': - return t('social', '{account} liked your post', { account: this.notification.account.acct }) - case 'poll': - return t('social', '{account} ended the poll', { account: this.notification.account.acct }) - case 'update': - return t('social', '{account} edited a status', { account: this.notification.account.acct }) - case 'admin.sign_up': - return t('social', '{account} signed up', { account: this.notification.account.acct }) - case 'admin.report': - return t('social', '{account} filed a report', { account: this.notification.account.acct }) - default: - return '' - } + return notificationSummary(this.notification) }, }, methods: { diff --git a/src/components/TimelineList.vue b/src/components/TimelineList.vue index 9d31b193..0141063c 100644 --- a/src/components/TimelineList.vue +++ b/src/components/TimelineList.vue @@ -22,7 +22,7 @@ <template> <div class="social__timeline"> - <transition-group name="list" tag="div"> + <transition-group name="list" tag="ul"> <TimelineEntry v-for="entry in timeline" :key="entry.id" :item="entry" diff --git a/src/components/TimelinePost.vue b/src/components/TimelinePost.vue index e04e70d7..5d504788 100644 --- a/src/components/TimelinePost.vue +++ b/src/components/TimelinePost.vue @@ -44,7 +44,7 @@ </span> </template> </NcButton> - <NcButton v-if="item.visibility === 'public' || item.visibility === 'followers'" + <NcButton v-if="item.visibility === 'public' || item.visibility === 'unlisted'" :title="t('social', 'Boost')" type="tertiary-no-background" @click="boost"> @@ -208,10 +208,10 @@ export default { getSinglePostTimeline(e) { // Display internal or external post if (!this.isLocal) { + // TODO - fix if (this.type === 'Note') { window.open(this.item.id) } else if (this.type === 'Announce') { - // TODO window.open(this.item.object) } else { logger.warn("Don't know what to do with posts of type " + this.type, { post: this.item }) @@ -269,7 +269,6 @@ export default { padding: 4px 8px; font-size: 15px; line-height: 1.6em; - position: relative; border-radius: 8px; ::v-deep a.widget-default { @@ -304,7 +303,7 @@ export default { } .post-visibility { - opacity: 0.5; + color: var(--color-text-lighter); background-position: right; } diff --git a/src/dashboard.js b/src/dashboard.js index bb0adbc5..56a6b1a3 100644 --- a/src/dashboard.js +++ b/src/dashboard.js @@ -26,8 +26,11 @@ Vue.prototype.OC = window.OC document.addEventListener('DOMContentLoaded', function() { OCA.Dashboard.register('social_notifications', (el, { widget }) => { const View = Vue.extend(Dashboard) + /* eslint-disable-next-line no-new */ new View({ propsData: { title: widget.title }, - }).$mount(el) + el, + name: 'SocialDashboard', + }) }) }) diff --git a/src/main.js b/src/main.js index 57ea3e25..98f7eb92 100644 --- a/src/main.js +++ b/src/main.js @@ -57,7 +57,10 @@ Vue.use(VueMasonry) /* eslint-disable-next-line no-new */ new Vue({ + el: '#content', + // eslint-disable-next-line vue/match-component-file-name + name: 'SocialRoot', router, render: h => h(App), store, -}).$mount('#content') +}) diff --git a/src/services/notifications.js b/src/services/notifications.js new file mode 100644 index 00000000..44a2b7bc --- /dev/null +++ b/src/services/notifications.js @@ -0,0 +1,32 @@ +import { translate } from '@nextcloud/l10n' + +/** + * @param {import("../types/Mastodon").Notification} notification + * @return {string} + */ +export function notificationSummary(notification) { + switch (notification.type) { + case 'mention': + return translate('social', '{account} mentioned you', { account: notification.account.acct }) + case 'status': + return translate('social', '{account} posted a status', { account: notification.account.acct }) + case 'reblog': + return translate('social', '{account} boosted your post', { account: notification.account.acct }) + case 'follow': + return translate('social', '{account} started to follow you', { account: notification.account.acct }) + case 'follow_request': + return translate('social', '{account} requested to follow you', { account: notification.account.acct }) + case 'favourite': + return translate('social', '{account} liked your post', { account: notification.account.acct }) + case 'poll': + return translate('social', '{account} ended the poll', { account: notification.account.acct }) + case 'update': + return translate('social', '{account} edited a status', { account: notification.account.acct }) + case 'admin.sign_up': + return translate('social', '{account} signed up', { account: notification.account.acct }) + case 'admin.report': + return translate('social', '{account} filed a report', { account: notification.account.acct }) + default: + return '' + } +} diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue index dab943e9..adc155b8 100644 --- a/src/views/Dashboard.vue +++ b/src/views/Dashboard.vue @@ -47,6 +47,7 @@ import { generateUrl } from '@nextcloud/router' import { showError } from '@nextcloud/dialogs' import NcDashboardWidget from '@nextcloud/vue/dist/Components/NcDashboardWidget.js' import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js' +import { notificationSummary } from '../services/notifications.js' export default { name: 'Dashboard', @@ -121,25 +122,19 @@ export default { }, 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) + async fetchNotifications() { + const url = generateUrl('apps/social/api/v1/notifications') + + try { + + const response = await axios.get(url) + if (response.data) { + this.processNotifications(response.data) this.state = 'ok' } else { this.state = 'error' } - }).catch((error) => { + } catch (error) { clearInterval(this.loop) if (error.response?.status && error.response.status >= 400) { showError(t('social', 'Failed to get Social notifications')) @@ -148,8 +143,9 @@ export default { // there was an error in notif processing console.error(error) } - }) + } }, + /** @param {import('../types/Mastodon.js').Notification[]} newNotifications */ processNotifications(newNotifications) { if (this.lastTimestamp !== 0) { // just add those which are more recent than our most recent one @@ -166,55 +162,46 @@ export default { this.notifications = this.filter(newNotifications) } }, + /** @param {import('../types/Mastodon.js').Notification[]} notifications */ filter(notifications) { return notifications - // TODO check if we need to filter - /* return notifications.filter((n) => { - return (n.type === 'something' || n.subtype === 'somethingElse') - }) */ }, + /** @param {import('../types/Mastodon.js').Notification} n */ getMainText(n) { - if (n.subtype === 'Follow') { - return t('social', '{account} is following you', { account: this.getActorName(n) }) - } - if (n.subtype === 'Like') { - return t('social', '{account} liked your post', { account: this.getActorName(n) }) - } + return notificationSummary(n) }, + /** @param {import('../types/Mastodon.js').Notification} n */ getAvatarUrl(n) { - return undefined - // TODO get external and internal avatars - /* return this.getActorAccountName(n) - ? generateUrl('???') - : undefined */ + return n.account.avatar }, + /** @param {import('../types/Mastodon.js').Notification} n */ getActorName(n) { - return n.actor_info && n.actor_info.type === 'Person' && n.actor_info.preferredUsername - ? n.actor_info.preferredUsername - : '' + return n.account.display_name }, + /** @param {import('../types/Mastodon.js').Notification} n */ getActorAccountName(n) { - return n.actor_info && n.actor_info.type === 'Person' && n.actor_info.account - ? n.actor_info.account - : '' + return n.account.acct }, + /** @param {import('../types/Mastodon.js').Notification} n */ getNotificationTarget(n) { - if (n.subtype === 'Follow') { + if (n.type === 'follow') { return generateUrl('/apps/social/@' + this.getActorAccountName(n) + '/') } return this.showMoreUrl }, + /** @param {import('../types/Mastodon.js').Notification} n */ getSubline(n) { - if (n.subtype === 'Follow') { + if (n.type === 'follow') { return this.getActorAccountName(n) } - if (n.subtype === 'Like') { + if (n.type === 'favourite') { return this.getActorAccountName(n) } return '' }, + /** @param {import('../types/Mastodon.js').Notification} n */ getNotificationTypeImage(n) { - if (n.subtype === 'Follow') { + if (n.type === 'follow') { return generateUrl('/svg/social/add_user') } return '' diff --git a/src/views/ProfilePageIntegration.vue b/src/views/ProfilePageIntegration.vue index 769ccd1e..8771a19e 100644 --- a/src/views/ProfilePageIntegration.vue +++ b/src/views/ProfilePageIntegration.vue @@ -1,7 +1,7 @@ <template> <div> <h2>Social</h2> - <transition-group name="list" tag="div"> + <transition-group name="list" tag="ul"> <TimelineEntry v-for="entry in timeline" :key="entry.id" :item="entry" /> @@ -42,16 +42,14 @@ export default { beforeMount() { const uid = this.userId - axios.get(generateUrl(`apps/social/api/v1/account/${uid}/info`)).then((response) => { - this.accountInfo = response.data.result.account + axios.get(generateUrl(`apps/social/api/v1/global/account/info?account=${uid}`)).then(({ data }) => { + this.accountInfo = data logger.log(this.accountInfo) }) - const since = Math.floor(Date.now() / 1000) + 1 - - axios.get(generateUrl(`apps/social/api/v1/account/${uid}/stream?limit=25&since=${since}`)).then(({ data }) => { + axios.get(generateUrl(`apps/social/api/v1/accounts/${uid}/statuses`)).then(({ data }) => { + this.timeline = data logger.log(this.timeline) - this.timeline = data.result }) }, } |