diff options
-rw-r--r-- | appinfo/routes.php | 2 | ||||
-rw-r--r-- | lib/Db/SocialLimitsQueryBuilder.php | 9 | ||||
-rw-r--r-- | lib/Db/StreamRequest.php | 4 | ||||
-rw-r--r-- | src/components/Composer.vue | 15 | ||||
-rw-r--r-- | src/components/EmptyContent.vue | 5 | ||||
-rw-r--r-- | src/components/FollowButton.vue | 11 | ||||
-rw-r--r-- | src/components/PostAttachment.vue | 32 | ||||
-rw-r--r-- | src/components/ProfileInfo.vue | 19 | ||||
-rw-r--r-- | src/components/TimelineEntry.vue | 32 | ||||
-rw-r--r-- | src/components/TimelineList.vue | 7 | ||||
-rw-r--r-- | src/components/TimelinePost.vue | 31 | ||||
-rw-r--r-- | src/mixins/accountMixins.js | 48 | ||||
-rw-r--r-- | src/mixins/serverData.js | 16 | ||||
-rw-r--r-- | src/store/account.js | 14 | ||||
-rw-r--r-- | src/store/timeline.js | 69 | ||||
-rw-r--r-- | src/views/OStatus.vue | 45 | ||||
-rw-r--r-- | src/views/Profile.vue | 17 | ||||
-rw-r--r-- | src/views/TimelineSinglePost.vue | 62 |
18 files changed, 294 insertions, 144 deletions
diff --git a/appinfo/routes.php b/appinfo/routes.php index f88528b8..077c37ee 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -50,7 +50,7 @@ return [ ['name' => 'Navigation#resizedGetPublic', 'url' => '/document/public/resized', 'verb' => 'GET'], ['name' => 'ActivityPub#actor', 'url' => '/users/{username}', 'verb' => 'GET'], - ['name' => 'ActivityPub#actorAlias', 'url' => '/@{username}/', 'verb' => 'GET'], + ['name' => 'ActivityPub#actorAlias', 'url' => '/@{username}', 'verb' => 'GET'], ['name' => 'ActivityPub#inbox', 'url' => '/@{username}/inbox', 'verb' => 'POST'], ['name' => 'ActivityPub#getInbox', 'url' => '/@{username}/inbox', 'verb' => 'GET'], ['name' => 'ActivityPub#sharedInbox', 'url' => '/inbox', 'verb' => 'POST'], diff --git a/lib/Db/SocialLimitsQueryBuilder.php b/lib/Db/SocialLimitsQueryBuilder.php index d3a4ff47..50877b8b 100644 --- a/lib/Db/SocialLimitsQueryBuilder.php +++ b/lib/Db/SocialLimitsQueryBuilder.php @@ -76,8 +76,15 @@ class SocialLimitsQueryBuilder extends SocialCrossQueryBuilder { * Limit the request to the Id (string) * * @param string $id + * @param bool $prim */ - public function limitToInReplyTo(string $id) { + public function limitToInReplyTo(string $id, bool $prim = false) { + if ($prim) { + $this->limitToDBField('in_reply_to_prim', $this->prim($id), false); + + return; + } + $this->limitToDBField('in_reply_to', $id, false); } diff --git a/lib/Db/StreamRequest.php b/lib/Db/StreamRequest.php index f9d86249..7e5ec825 100644 --- a/lib/Db/StreamRequest.php +++ b/lib/Db/StreamRequest.php @@ -274,11 +274,7 @@ class StreamRequest extends StreamRequestBuilder { $qb->limitToInReplyTo($id); $qb->limitPaginate($since, $limit); - $expr = $qb->expr(); $qb->linkToCacheActors('ca', 's.attributed_to_prim'); - - $qb->andWhere($expr->eq('s.attributed_to', 'ca.id_prim')); - if ($asViewer) { $qb->limitToViewer('sd', 'f', true); $qb->leftJoinStreamAction(); diff --git a/src/components/Composer.vue b/src/components/Composer.vue index f14a93a3..f1c0121f 100644 --- a/src/components/Composer.vue +++ b/src/components/Composer.vue @@ -39,7 +39,7 @@ <span>In reply to</span> <actor-avatar :actor="replyTo.actor_info" :size="16" /> <strong>{{ replyTo.actor_info.account }}</strong> - <a class="icon-close" @click="replyTo=null" /> + <a class="icon-close" @click="closeReply()" /> </p> <div class="reply-to-preview"> {{ replyTo.content }} @@ -610,6 +610,7 @@ export default { mounted() { this.$root.$on('composer-reply', (data) => { this.replyTo = data + this.type = 'direct' }) }, methods: { @@ -737,7 +738,7 @@ export default { let contentHtml = element.innerHTML - // Extract mentions from content and create an array ot of them + // Extract mentions from content and create an array out of them let to = [] const mentionRegex = /<span class="mention"[^>]+><a[^>]+><img[^>]+>@([\w-_.]+@[\w-.]+)/g let match = null @@ -748,6 +749,11 @@ export default { } } while (match) + // Add author of original post in case of reply + if (this.replyTo !== null) { + to.push(this.replyTo.actor_info.account) + } + // Extract hashtags from content and create an array ot of them const hashtagRegex = />#([^<]+)</g let hashtags = [] @@ -824,6 +830,11 @@ export default { }) }, + closeReply() { + this.replyTo = null + // View may want to hide the composer + this.$store.commit('setComposerDisplayStatus', false) + }, remoteSearchAccounts(text) { return axios.get(generateUrl('apps/social/api/v1/global/accounts/search?search=' + text)) }, diff --git a/src/components/EmptyContent.vue b/src/components/EmptyContent.vue index 82e62ef0..db76d4e7 100644 --- a/src/components/EmptyContent.vue +++ b/src/components/EmptyContent.vue @@ -22,7 +22,10 @@ <template> <div class="emptycontent"> - <img :src="imageUrl" class="icon-illustration" alt=""> + <img v-if="item.image" + :src="imageUrl" + class="icon-illustration" + alt=""> <h2>{{ item.title }}</h2> <p>{{ item.description }}</p> </div> diff --git a/src/components/FollowButton.vue b/src/components/FollowButton.vue index d2c76953..73f6704c 100644 --- a/src/components/FollowButton.vue +++ b/src/components/FollowButton.vue @@ -22,7 +22,7 @@ <template> <!-- Show button only if user is authenticated and she is not the same as the account viewed --> - <div v-if="!serverData.public && actorInfo && actorInfo.viewerLink!='viewer'"> + <div v-if="!serverData.public && accountInfo && accountInfo.viewerLink!='viewer'"> <button v-if="isCurrentUserFollowing" :class="{'icon-loading-small': followLoading}" @click="unfollow()" @mouseover="followingText=t('social', 'Unfollow')" @mouseleave="followingText=t('social', 'Following')"> @@ -36,17 +36,23 @@ </template> <script> +import accountMixins from '../mixins/accountMixins' import currentUser from '../mixins/currentUserMixin' export default { name: 'FollowButton', mixins: [ + accountMixins, currentUser ], props: { account: { type: String, default: '' + }, + uid: { + type: String, + default: '' } }, data: function() { @@ -55,9 +61,6 @@ export default { } }, computed: { - actorInfo() { - return this.$store.getters.getAccount(this.account) - }, followLoading() { return false }, diff --git a/src/components/PostAttachment.vue b/src/components/PostAttachment.vue index 0f70552e..67210b3e 100644 --- a/src/components/PostAttachment.vue +++ b/src/components/PostAttachment.vue @@ -1,7 +1,7 @@ <template> <masonry> <div v-for="(item, index) in attachments" :key="index"> - <img :src="generateUrl('/apps/social/document/get/resized?id=' + item.id)" @click="showModal(index)"> + <img :src="imageUrl(item)" @click="showModal(index)"> </div> <modal v-show="modal" :has-previous="current > 0" :has-next="current < (attachments.length - 1)" size="full" @close="closeModal" @previous="showPrevious" @@ -15,6 +15,7 @@ <script> +import serverData from '../mixins/serverData' import Modal from '@nextcloud/vue/dist/Components/Modal' import { generateUrl } from '@nextcloud/router' @@ -23,7 +24,9 @@ export default { components: { Modal }, - mixins: [], + mixins: [ + serverData + ], props: { attachments: { type: Array, @@ -37,7 +40,24 @@ export default { } }, methods: { - displayResizedImage() { + /** + * @function imageUrl + * @description Returns the URL where to get a resized version of the attachement + * @param {object} item - The attachment + * @returns {string} The URL + */ + imageUrl(item) { + if (this.serverData.public) { + return generateUrl('/apps/social/document/public/resized?id=' + item.id) + } else { + return generateUrl('/apps/social/document/get/resized?id=' + item.id) + } + }, + /** + * @function displayImage + * @description Displays the currently selected attachment's image + */ + displayImage() { var canvas = this.$refs.modalCanvas var ctx = canvas.getContext('2d') var img = new Image() @@ -60,7 +80,7 @@ export default { }, showModal(idx) { this.current = idx - this.displayResizedImage() + this.displayImage() this.modal = true }, closeModal() { @@ -68,11 +88,11 @@ export default { }, showPrevious() { this.current-- - this.displayResizedImage() + this.displayImage() }, showNext() { this.current++ - this.displayResizedImage() + this.displayImage() } } } diff --git a/src/components/ProfileInfo.vue b/src/components/ProfileInfo.vue index a5911fa7..899494a2 100644 --- a/src/components/ProfileInfo.vue +++ b/src/components/ProfileInfo.vue @@ -21,7 +21,7 @@ --> <template> - <div v-if="account && accountInfo" class="user-profile"> + <div v-if="profileAccount && accountInfo" class="user-profile"> <div> <avatar v-if="accountInfo.local" :user="localUid" :disable-tooltip="true" :size="128" /> @@ -34,7 +34,7 @@ {{ accountInfo.website.value }} </a> </p> - <follow-button :account="accountInfo.account" /> + <follow-button :account="accountInfo.account" :uid="uid" /> <button v-if="serverData.public" class="primary" @click="followRemote"> {{ t('social', 'Follow') }} </button> @@ -97,6 +97,7 @@ </style> <script> import Avatar from '@nextcloud/vue/dist/Components/Avatar' +import accountMixins from '../mixins/accountMixins' import serverData from '../mixins/serverData' import currentUser from '../mixins/currentUserMixin' import follow from '../mixins/follow' @@ -110,8 +111,9 @@ export default { Avatar }, mixins: [ - serverData, + accountMixins, currentUser, + serverData, follow ], props: { @@ -130,9 +132,6 @@ export default { // Returns only the local part of a username return (this.uid.indexOf('@') === -1) ? this.uid : this.uid.substr(0, this.uid.indexOf('@')) }, - account() { - return (this.uid.indexOf('@') === -1) ? this.uid + '@' + this.hostname : this.uid - }, displayName() { if (typeof this.accountInfo.name !== 'undefined' && this.accountInfo.name !== '') { return this.accountInfo.name @@ -140,13 +139,11 @@ export default { if (typeof this.accountInfo.preferredUsername !== 'undefined' && this.accountInfo.preferredUsername !== '') { return this.accountInfo.preferredUsername } - return this.account - }, - accountInfo: function() { - return this.$store.getters.getAccount(this.account) + return this.profileAccount }, getCount() { - return (field) => this.accountInfo.details.count ? this.accountInfo.details.count[field] : '' + let account = this.accountInfo + return (field) => account.details.count ? account.details.count[field] : '' }, avatarUrl() { return generateUrl('/apps/social/api/v1/global/actor/avatar?id=' + this.accountInfo.id) diff --git a/src/components/TimelineEntry.vue b/src/components/TimelineEntry.vue index d6815280..61833343 100644 --- a/src/components/TimelineEntry.vue +++ b/src/components/TimelineEntry.vue @@ -1,5 +1,5 @@ <template> - <div class="timeline-entry" @click="getSinglePostTimeline"> + <div class="timeline-entry"> <div v-if="item.type === 'SocialAppNotification'"> {{ actionSummary }} </div> @@ -30,7 +30,6 @@ </template> <script> -import Logger from '../logger' import TimelinePost from './TimelinePost.vue' export default { @@ -95,35 +94,6 @@ export default { } }, methods: { - getSinglePostTimeline(e) { - - // Do not call the single-post view when clicking on a link, a post attachment miniature or the post's author - if (e.target.tagName === 'A' || e.target.tagName === 'IMG' || e.target.className.startsWith('post-author')) { - Logger.debug('will not call single-post', { event: e }) - return - } - - // Display internal or external post - if (!this.item.local) { - if (this.item.type === 'Note') { - window.open(this.item.id) - } else if (this.item.type === 'Announce') { - window.open(this.item.object) - } else { - Logger.warn("Don't know what to do with posts of type " + this.item.type, { post: this.item }) - } - } else { - this.$router.push({ name: 'single-post', - params: { - account: this.item.actor_info.preferredUsername, - id: this.item.id, - localId: this.item.id.split('/')[this.item.id.split('/').length - 1], - type: 'single-post' - } - }) - } - - }, userDisplayName(actorInfo) { return actorInfo.name !== '' ? actorInfo.name : actorInfo.preferredUsername } diff --git a/src/components/TimelineList.vue b/src/components/TimelineList.vue index f42edb4b..9e86912a 100644 --- a/src/components/TimelineList.vue +++ b/src/components/TimelineList.vue @@ -60,6 +60,7 @@ import InfiniteLoading from 'vue-infinite-loading' import TimelineEntry from './TimelineEntry.vue' import CurrentUserMixin from './../mixins/currentUserMixin' import EmptyContent from './EmptyContent.vue' +import Logger from '../logger.js' export default { name: 'Timeline', @@ -113,6 +114,9 @@ export default { tags: { image: 'img/undraw/profile.svg', title: t('social', 'No posts found for this tag') + }, + 'single-post': { + title: t('social', 'No replies found') } } } @@ -122,6 +126,7 @@ export default { if (typeof this.emptyContent[this.$route.params.type] !== 'undefined') { return this.emptyContent[this.$route.params.type] } + if (typeof this.emptyContent[this.$route.name] !== 'undefined') { let content = this.emptyContent[this.$route.name] // Change text on profile page when accessed by another user or a public (non-authenticated) user @@ -130,7 +135,9 @@ export default { } return this.$route.name === 'timeline' ? this.emptyContent['default'] : content } + // Fallback + Logger.log('Did not find any empty content for this route', { 'routeType': this.$route.params.type, 'routeName': this.$route.name }) return this.emptyContent.default }, timeline: function() { diff --git a/src/components/TimelinePost.vue b/src/components/TimelinePost.vue index d3ff2318..411dc5ff 100644 --- a/src/components/TimelinePost.vue +++ b/src/components/TimelinePost.vue @@ -26,9 +26,9 @@ </span> </a> </div> - <div :data-timestamp="timestamp" class="post-timestamp live-relative-timestamp"> + <a :data-timestamp="timestamp" class="post-timestamp live-relative-timestamp" @click="getSinglePostTimeline"> {{ relativeTimestamp }} - </div> + </a> </div> <!-- eslint-disable-next-line vue/no-v-html --> <div v-if="item.content" class="post-message"> @@ -64,6 +64,7 @@ import 'linkifyjs/string' import popoverMenu from './../mixins/popoverMenu' import currentUser from './../mixins/currentUserMixin' import PostAttachment from './PostAttachment.vue' +import Logger from '../logger' import MessageContent from './MessageContent' import moment from '@nextcloud/moment' import { generateUrl } from '@nextcloud/router' @@ -140,10 +141,36 @@ export default { } }, methods: { + /** + * @function getSinglePostTimeline + * @description Opens the timeline of the post clicked + */ + getSinglePostTimeline(e) { + // Display internal or external post + if (!this.item.local) { + if (this.item.type === 'Note') { + window.open(this.item.id) + } else if (this.item.type === 'Announce') { + window.open(this.item.object) + } else { + Logger.warn("Don't know what to do with posts of type " + this.item.type, { post: this.item }) + } + } else { + this.$router.push({ name: 'single-post', + params: { + account: this.item.actor_info.preferredUsername, + id: this.item.id, + localId: this.item.id.split('/')[this.item.id.split('/').length - 1], + type: 'single-post' + } + }) + } + }, userDisplayName(actorInfo) { return actorInfo.name !== '' ? actorInfo.name : actorInfo.preferredUsername }, reply() { + this.$store.commit('setComposerDisplayStatus', true) this.$root.$emit('composer-reply', this.item) }, boost() { diff --git a/src/mixins/accountMixins.js b/src/mixins/accountMixins.js new file mode 100644 index 00000000..5f1a52fb --- /dev/null +++ b/src/mixins/accountMixins.js @@ -0,0 +1,48 @@ +/* + * @copyright Copyright (c) 2019 Cyrille Bollu <cyrpub@bollu.be> + * + * @author Cyrille Bollu <cyrpub@bollu.be> + * + * @license GNU AGPL version 3 or any later version + * + * @file provides global account related methods + * + * @mixin + * + * 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 serverData from './serverData' + +export default { + mixins: [ + serverData + ], + computed: { + /** @function Returns the complete account name */ + profileAccount() { + return (this.uid.indexOf('@') === -1) ? this.uid + '@' + this.hostname : this.uid + }, + /** @functions Returns detailed information about an account (account must be loaded in the store first) */ + accountInfo() { + return this.$store.getters.getAccount(this.profileAccount) + }, + /** @function Somewhat duplicate with accountInfo(), but needed (for some reason) to avoid glitches + * where components would first show "user not found" before display an account's account info */ + accountLoaded() { + return this.$store.getters.accountLoaded(this.profileAccount) + } + } +} diff --git a/src/mixins/serverData.js b/src/mixins/serverData.js index 1fdcbfd1..eff54329 100644 --- a/src/mixins/serverData.js +++ b/src/mixins/serverData.js @@ -1,6 +1,10 @@ /* * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> * + * @file Provides global methods for using the serverData structure. + * + * @mixin + * * @author Julius Härtl <jus@bitgrid.net> * * @license GNU AGPL version 3 or any later version @@ -22,7 +26,17 @@ export default { computed: { - serverData: function() { + /** @description Returns the serverData object + * @property {String} account - The account that the user wants to follow (Only in 'OStatus.vue') + * @property cliUrl + * @property cloudAddress + * @property firstrun + * @property isAdmin + * @property {String} local - The local part of the account that the user wants to follow + * @property {boolean} public - False when the page is accessed by an authenticated user. True otherwise + * @property setup + */ + serverData() { return this.$store.getters.getServerData }, hostname() { diff --git a/src/store/account.js b/src/store/account.js index 91d7b272..f23295cc 100644 --- a/src/store/account.js +++ b/src/store/account.js @@ -46,13 +46,10 @@ const mutations = { let users = [] for (var index in data) { const actor = data[index].actor_info - if (typeof actor !== 'undefined' && account !== actor.account) { - users.push(actor.id) - addAccount(state, { - actorId: actor.id, - data: actor - }) - } + addAccount(state, { + actorId: actor.id, + data: actor + }) } Vue.set(state.accounts[_getActorIdForAccount(account)], 'followersList', users) }, @@ -79,6 +76,9 @@ const mutations = { } const getters = { + getAllAccounts(state) { + return (account) => { return state.accounts } + }, getAccount(state, getters) { return (account) => { return state.accounts[_getActorIdForAccount(account)] diff --git a/src/store/timeline.js b/src/store/timeline.js index e61a1219..031f3306 100644 --- a/src/store/timeline.js +++ b/src/store/timeline.js @@ -1,6 +1,8 @@ /* * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> * + * @file Timeline related store + * * @author Julius Härtl <jus@bitgrid.net> * @author Jonas Sulzer <jonas@violoncello.ch> * @@ -26,12 +28,31 @@ import axios from '@nextcloud/axios' import Vue from 'vue' import { generateUrl } from '@nextcloud/router' +/** + * @property {object} timeline - The posts' collection + * @property {int} since - Time (EPOCH) of the most recent post + * @property {string} type - Timeline's type: 'home', 'single-post',... + * @property {object} params - Timeline's parameters + * @property {string} account - + */ const state = { timeline: {}, since: Math.floor(Date.now() / 1000) + 1, type: 'home', + /** + * @namespace params + * @property {string} account ??? + * @property {string} id + * @property {string} localId + * @property {string} type ??? + */ params: {}, - account: '' + account: '', + /* Tells whether the composer should be displayed or not. + * It's up to the view to honor this status or not. + * @member {boolean} + */ + composerDisplayStatus: false } const mutations = { addToTimeline(state, data) { @@ -53,6 +74,9 @@ const mutations = { setTimelineParams(state, params) { state.params = params }, + setComposerDisplayStatus(state, status) { + state.composerDisplayStatus = status + }, setAccount(state, account) { state.account = account }, @@ -90,6 +114,9 @@ const mutations = { } } const getters = { + getComposerDisplayStatus(state) { + return state.composerDisplayStatus + }, getTimeline(state) { return Object.values(state.timeline).sort(function(a, b) { return b.publishedTime - a.publishedTime @@ -120,12 +147,11 @@ const actions = { post(context, post) { return new Promise((resolve, reject) => { axios.post(generateUrl('apps/social/api/v1/post'), { data: post }).then((response) => { - // eslint-disable-next-line no-console - console.log('Post created with token ' + response.data.result.token) + Logger.info('Post created with token ' + response.data.result.token) resolve(response) }).catch((error) => { OC.Notification.showTemporary('Failed to create a post') - console.error('Failed to create a post', error.response) + Logger.error('Failed to create a post', { 'error': error.response }) reject(error) }) }) @@ -133,11 +159,10 @@ const actions = { postDelete(context, post) { return axios.delete(generateUrl(`apps/social/api/v1/post?id=${post.id}`)).then((response) => { context.commit('removePost', post) - // eslint-disable-next-line no-console - console.log('Post deleted with token ' + response.data.result.token) + Logger.info('Post deleted with token ' + response.data.result.token) }).catch((error) => { OC.Notification.showTemporary('Failed to delete the post') - console.error('Failed to delete the post', error) + Logger.error('Failed to delete the post', { 'error': error }) }) }, postLike(context, { post, parentAnnounce }) { @@ -147,7 +172,7 @@ const actions = { resolve(response) }).catch((error) => { OC.Notification.showTemporary('Failed to like post') - console.error('Failed to like post', error.response) + Logger.error('Failed to like post', { 'error': error.response }) reject(error) }) }) @@ -161,19 +186,18 @@ const actions = { } }).catch((error) => { OC.Notification.showTemporary('Failed to unlike post') - console.error('Failed to unlike post', error) + Logger.error('Failed to unlike post', { 'error': error }) }) }, postBoost(context, { post, parentAnnounce }) { return new Promise((resolve, reject) => { axios.post(generateUrl(`apps/social/api/v1/post/boost?postId=${post.id}`)).then((response) => { context.commit('boostPost', { post, parentAnnounce }) - // eslint-disable-next-line no-console - console.log('Post boosted with token ' + response.data.result.token) + Logger.info('Post boosted with token ' + response.data.result.token) resolve(response) }).catch((error) => { OC.Notification.showTemporary('Failed to create a boost post') - console.error('Failed to create a boost post', error.response) + Logger.error('Failed to create a boost post', { 'error': error.response }) reject(error) }) }) @@ -181,11 +205,10 @@ const actions = { postUnBoost(context, { post, parentAnnounce }) { return axios.delete(generateUrl(`apps/social/api/v1/post/boost?postId=${post.id}`)).then((response) => { context.commit('unboostPost', { post, parentAnnounce }) - // eslint-disable-next-line no-console - console.log('Boost deleted with token ' + response.data.result.token) + Logger.info('Boost deleted with token ' + response.data.result.token) }).catch((error) => { OC.Notification.showTemporary('Failed to delete the boost') - console.error('Failed to delete the boost', error) + Logger.error('Failed to delete the boost', { 'error': error }) }) }, refreshTimeline(context) { @@ -216,22 +239,8 @@ const actions = { throw response.message } - let result = [] - - // Also load replies when displaying a single post timeline - if (state.type === 'single-post') { - result.push(response.data) - // axios.get(generateUrl(``)).then((response) => { - // if (response.status !== -1) { - // result.concat(response.data.result) - // } - // } - } else { - result = response.data.result - } - // Add results to timeline - context.commit('addToTimeline', result) + context.commit('addToTimeline', response.data.result) return response.data }) diff --git a/src/views/OStatus.vue b/src/views/OStatus.vue index bdbe822c..2ce96cff 100644 --- a/src/views/OStatus.vue +++ b/src/views/OStatus.vue @@ -1,5 +1,5 @@ <template> - <div v-if="accountInfo"> + <div v-if="account"> <div v-if="!serverData.local"> <h2>{{ t('social', 'Follow on Nextcloud Social') }}</h2> <p>{{ t('social', 'Hello') }} <avatar :user="currentUser.uid" :size="16" />{{ currentUser.displayName }}</p> @@ -23,6 +23,7 @@ </button> </div> </div> + <!-- Some unauthenticated user wants to follow a local account --> <div v-if="serverData.local"> <p>{{ t('social', 'You are going to follow:') }}</p> <avatar :user="serverData.local" :disab |