From 6b6878bde06b375b1e715a3557f153acc73a8af0 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Mon, 18 Feb 2019 17:49:32 +0300 Subject: [PATCH 01/14] Added moderation menu --- package.json | 2 + src/App.scss | 8 + src/boot/after_store.js | 1 + src/components/delete_button/delete_button.js | 6 +- src/components/dialog_modal/dialog_modal.js | 14 ++ src/components/dialog_modal/dialog_modal.vue | 92 ++++++++++ .../moderation_tools/moderation_tools.js | 106 ++++++++++++ .../moderation_tools/moderation_tools.vue | 158 ++++++++++++++++++ src/components/notification/notification.js | 3 + src/components/notification/notification.vue | 2 +- src/components/popper/popper.scss | 70 ++++++++ src/components/user_card/user_card.js | 13 +- src/components/user_card/user_card.vue | 2 + src/components/user_profile/user_profile.js | 4 +- src/i18n/en.json | 24 ++- src/i18n/ru.json | 24 ++- src/modules/statuses.js | 10 ++ src/modules/users.js | 22 +++ src/services/api/api.service.js | 90 ++++++++++ .../backend_interactor_service.js | 30 ++++ .../entity_normalizer.service.js | 19 ++- yarn.lock | 10 ++ 22 files changed, 697 insertions(+), 13 deletions(-) create mode 100644 src/components/dialog_modal/dialog_modal.js create mode 100644 src/components/dialog_modal/dialog_modal.vue create mode 100644 src/components/moderation_tools/moderation_tools.js create mode 100644 src/components/moderation_tools/moderation_tools.vue create mode 100644 src/components/popper/popper.scss diff --git a/package.json b/package.json index 03228133..c80e0f63 100644 --- a/package.json +++ b/package.json @@ -24,12 +24,14 @@ "node-sass": "^3.10.1", "object-path": "^0.11.3", "phoenix": "^1.3.0", + "popper.js": "^1.14.7", "sanitize-html": "^1.13.0", "sass-loader": "^4.0.2", "vue": "^2.5.13", "vue-chat-scroll": "^1.2.1", "vue-compose": "^0.7.1", "vue-i18n": "^7.3.2", + "vue-popperjs": "^2.0.3", "vue-router": "^3.0.1", "vue-template-compiler": "^2.3.4", "vue-timeago": "^3.1.2", diff --git a/src/App.scss b/src/App.scss index 5fc0dd27..b1c65ade 100644 --- a/src/App.scss +++ b/src/App.scss @@ -101,6 +101,14 @@ button { background-color: $fallback--bg; background-color: var(--bg, $fallback--bg) } + + &.danger { + // TODO: add better color variable + color: $fallback--text; + color: var(--alertErrorPanelText, $fallback--text); + background-color: $fallback--alertError; + background-color: var(--alertError, $fallback--alertError); + } } label.select { diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 862a534d..bb593026 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -210,6 +210,7 @@ const getNodeInfo = async ({ store }) => { const frontendVersion = window.___pleromafe_commit_hash store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion }) + store.dispatch('setInstanceOption', { name: 'tagPolicyAvailable', value: metadata.federation.mrf_policies.includes('TagPolicy') }) } else { throw (res) } diff --git a/src/components/delete_button/delete_button.js b/src/components/delete_button/delete_button.js index f2920666..22f24625 100644 --- a/src/components/delete_button/delete_button.js +++ b/src/components/delete_button/delete_button.js @@ -10,7 +10,11 @@ const DeleteButton = { }, computed: { currentUser () { return this.$store.state.users.currentUser }, - canDelete () { return this.currentUser && this.currentUser.rights.delete_others_notice || this.status.user.id === this.currentUser.id } + canDelete () { + if (!this.currentUser) { return } + const superuser = this.currentUser.rights.moderator || this.currentUser.rights.admin + return superuser || this.status.user.id === this.currentUser.id + } } } diff --git a/src/components/dialog_modal/dialog_modal.js b/src/components/dialog_modal/dialog_modal.js new file mode 100644 index 00000000..f14e3fe9 --- /dev/null +++ b/src/components/dialog_modal/dialog_modal.js @@ -0,0 +1,14 @@ +const DialogModal = { + props: { + darkOverlay: { + default: true, + type: Boolean + }, + onCancel: { + default: () => {}, + type: Function + } + } +} + +export default DialogModal diff --git a/src/components/dialog_modal/dialog_modal.vue b/src/components/dialog_modal/dialog_modal.vue new file mode 100644 index 00000000..7621fb20 --- /dev/null +++ b/src/components/dialog_modal/dialog_modal.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js new file mode 100644 index 00000000..3eedeaa1 --- /dev/null +++ b/src/components/moderation_tools/moderation_tools.js @@ -0,0 +1,106 @@ +import DialogModal from '../dialog_modal/dialog_modal.vue' +import Popper from 'vue-popperjs/src/component/popper.js.vue' + +const FORCE_NSFW = 'mrf_tag:media-force-nsfw' +const STRIP_MEDIA = 'mrf_tag:media-strip' +const FORCE_UNLISTED = 'mrf_tag:force-unlisted' +const DISABLE_REMOTE_SUBSCRIPTION = 'mrf_tag:disable-remote-subscription' +const DISABLE_ANY_SUBSCRIPTION = 'mrf_tag:disable-any-subscription' +const SANDBOX = 'mrf_tag:sandbox' +const QUARANTINE = 'mrf_tag:quarantine' + +const ModerationTools = { + props: [ + 'user' + ], + data () { + return { + showDropDown: false, + tags: { + FORCE_NSFW, + STRIP_MEDIA, + FORCE_UNLISTED, + DISABLE_REMOTE_SUBSCRIPTION, + DISABLE_ANY_SUBSCRIPTION, + SANDBOX, + QUARANTINE + }, + showDeleteUserDialog: false + } + }, + components: { + DialogModal, + Popper + }, + computed: { + tagsSet () { + return new Set(this.user.tags) + }, + hasTagPolicy () { + return this.$store.state.instance.tagPolicyAvailable + } + }, + methods: { + toggleMenu () { + this.showDropDown = !this.showDropDown + }, + hasTag (tagName) { + return this.tagsSet.has(tagName) + }, + toggleTag (tag) { + const store = this.$store + if (this.tagsSet.has(tag)) { + store.state.api.backendInteractor.untagUser(this.user, tag).then(response => { + if (!response.ok) { return } + store.commit('untagUser', {user: this.user, tag}) + }) + } else { + store.state.api.backendInteractor.tagUser(this.user, tag).then(response => { + if (!response.ok) { return } + store.commit('tagUser', {user: this.user, tag}) + }) + } + }, + toggleRight (right) { + const store = this.$store + if (this.user.rights[right]) { + store.state.api.backendInteractor.deleteRight(this.user, right).then(response => { + if (!response.ok) { return } + store.commit('updateRight', {user: this.user, right: right, value: false}) + }) + } else { + store.state.api.backendInteractor.addRight(this.user, right).then(response => { + if (!response.ok) { return } + store.commit('updateRight', {user: this.user, right: right, value: true}) + }) + } + }, + toggleActivationStatus () { + const store = this.$store + const status = !!this.user.deactivated + store.state.api.backendInteractor.setActivationStatus(this.user, status).then(response => { + if (!response.ok) { return } + store.commit('updateActivationStatus', {user: this.user, status: status}) + }) + }, + deleteUserDialog (show) { + this.showDeleteUserDialog = show + }, + deleteUser () { + const store = this.$store + const user = this.user + const {id, name} = user + store.state.api.backendInteractor.deleteUser(user) + .then(e => { + this.$store.dispatch('markStatusesAsDeleted', status => user.id === status.user.id) + const isProfile = this.$route.name === 'external-user-profile' || this.$route.name === 'user-profile' + const isTargetUser = this.$route.params.name === name || this.$route.params.id === id + if (isProfile && isTargetUser) { + window.history.back() + } + }) + } + } +} + +export default ModerationTools diff --git a/src/components/moderation_tools/moderation_tools.vue b/src/components/moderation_tools/moderation_tools.vue new file mode 100644 index 00000000..c24a2280 --- /dev/null +++ b/src/components/moderation_tools/moderation_tools.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 42a48f3f..6aa6101f 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -21,6 +21,9 @@ const Notification = { }, userProfileLink (user) { return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) + }, + getUser (notification) { + return this.$store.state.users.usersObject[notification.action.user.id] } }, computed: { diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 8f532747..cac335ce 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -5,7 +5,7 @@
- +
diff --git a/src/components/popper/popper.scss b/src/components/popper/popper.scss new file mode 100644 index 00000000..0c30d625 --- /dev/null +++ b/src/components/popper/popper.scss @@ -0,0 +1,70 @@ +@import '../../_variables.scss'; + +.popper-wrapper { + z-index: 8; +} + +.popper-wrapper .popper__arrow { + width: 0; + height: 0; + border-style: solid; + position: absolute; + margin: 5px; +} + +.popper-wrapper[x-placement^="top"] { + margin-bottom: 5px; +} + +.popper-wrapper[x-placement^="top"] .popper__arrow { + border-width: 5px 5px 0 5px; + border-color: $fallback--bg transparent transparent transparent; + border-color: var(--bg, $fallback--bg) transparent transparent transparent; + bottom: -5px; + left: calc(50% - 5px); + margin-top: 0; + margin-bottom: 0; +} + +.popper-wrapper[x-placement^="bottom"] { + margin-top: 5px; +} + +.popper-wrapper[x-placement^="bottom"] .popper__arrow { + border-width: 0 5px 5px 5px; + border-color: transparent transparent $fallback--bg transparent; + border-color: transparent transparent var(--bg, $fallback--bg) transparent; + top: -5px; + left: calc(50% - 5px); + margin-top: 0; + margin-bottom: 0; +} + +.popper-wrapper[x-placement^="right"] { + margin-left: 5px; +} + +.popper-wrapper[x-placement^="right"] .popper__arrow { + border-width: 5px 5px 5px 0; + border-color: transparent $fallback--bg transparent transparent; + border-color: transparent var(--bg, $fallback--bg) transparent transparent; + left: -5px; + top: calc(50% - 5px); + margin-left: 0; + margin-right: 0; +} + +.popper-wrapper[x-placement^="left"] { + margin-right: 5px; +} + +.popper-wrapper[x-placement^="left"] .popper__arrow { + border-width: 5px 0 5px 5px; + border-color: transparent transparent transparent $fallback--bg; + border-color: transparent transparent transparent var(--bg, $fallback--bg); + right: -5px; + top: calc(50% - 5px); + margin-left: 0; + margin-right: 0; +} + diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index 197c61d5..1a100de3 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -1,5 +1,6 @@ import UserAvatar from '../user_avatar/user_avatar.vue' import RemoteFollow from '../remote_follow/remote_follow.vue' +import ModerationTools from '../moderation_tools/moderation_tools.vue' import { hex2rgb } from '../../services/color_convert/color_convert.js' import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' @@ -93,15 +94,17 @@ export default { } }, visibleRole () { - const validRole = (this.user.role === 'admin' || this.user.role === 'moderator') - const showRole = this.isOtherUser || this.user.show_role - - return validRole && showRole && this.user.role + const rights = this.user.rights + if (!rights) { return } + const validRole = rights.admin || rights.moderator + const roleTitle = rights.admin ? 'admin' : 'moderator' + return validRole && roleTitle } }, components: { UserAvatar, - RemoteFollow + RemoteFollow, + ModerationTools }, methods: { followUser () { diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 3259d1c5..b5c7fa24 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -99,6 +99,8 @@
+ +
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 1df06fe6..540de955 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -3,6 +3,7 @@ import get from 'lodash/get' import UserCard from '../user_card/user_card.vue' import FollowCard from '../follow_card/follow_card.vue' import Timeline from '../timeline/timeline.vue' +import ModerationTools from '../moderation_tools/moderation_tools.vue' import withLoadMore from '../../hocs/with_load_more/with_load_more' import withList from '../../hocs/with_list/with_list' @@ -155,7 +156,8 @@ const UserProfile = { UserCard, Timeline, FollowerList, - FriendList + FriendList, + ModerationTools } } diff --git a/src/i18n/en.json b/src/i18n/en.json index 026546cc..0bb58734 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -22,7 +22,8 @@ "generic_error": "An error occured", "optional": "optional", "show_more": "Show more", - "show_less": "Show less" + "show_less": "Show less", + "cancel": "Cancel" }, "image_cropper": { "crop_picture": "Crop picture", @@ -402,7 +403,26 @@ "block_progress": "Blocking...", "unmute": "Unmute", "unmute_progress": "Unmuting...", - "mute_progress": "Muting..." + "mute_progress": "Muting...", + "admin_menu": { + "moderation": "Moderation", + "grant_admin": "Grant Admin", + "revoke_admin": "Revoke Admin", + "grant_moderator": "Grant Moderator", + "revoke_moderator": "Revoke Moderator", + "activate_account": "Activate account", + "deactivate_account": "Deactivate account", + "delete_account": "Delete account", + "force_nsfw": "Mark all posts as NSFW", + "strip_media": "Remove media from posts", + "force_unlisted": "Force posts to be unlisted", + "sandbox": "Force posts to be followers-only", + "disable_remote_subscription": "Disallow following user from remote instances", + "disable_any_subscription": "Disallow following user at all", + "quarantine": "Disallow user posts from federating", + "delete_user": "Delete user", + "delete_user_confirmation": "Are you absolutely sure? This action cannot be undone." + } }, "user_profile": { "timeline_title": "User Timeline", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index 89aa43f4..5450f154 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -8,7 +8,8 @@ }, "general": { "apply": "Применить", - "submit": "Отправить" + "submit": "Отправить", + "cancel": "Отмена" }, "login": { "login": "Войти", @@ -311,7 +312,26 @@ "muted": "Игнорирую", "per_day": "в день", "remote_follow": "Читать удалённо", - "statuses": "Статусы" + "statuses": "Статусы", + "admin_menu": { + "moderation": "Опции модератора", + "grant_admin": "Сделать администратором", + "revoke_admin": "Забрать права администратора", + "grant_moderator": "Сделать модератором", + "revoke_moderator": "Забрать права модератора", + "activate_account": "Активировать аккаунт", + "deactivate_account": "Деактивировать аккаунт", + "delete_account": "Удалить аккаунт", + "force_nsfw": "Отмечать посты пользователя как NSFW", + "strip_media": "Убирать вложения из постов пользователя", + "force_unlisted": "Не добавлять посты в публичные ленты", + "sandbox": "Посты доступны только для подписчиков", + "disable_remote_subscription": "Запретить подписываться с удаленных серверов", + "disable_any_subscription": "Запретить подписываться на пользователя", + "quarantine": "Не федерировать посты пользователя", + "delete_user": "Удалить пользователя", + "delete_user_confirmation": "Вы уверены? Это действие нельзя отменить." + } }, "user_profile": { "timeline_title": "Лента пользователя" diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 8e0203e3..4007b0fc 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -378,6 +378,13 @@ export const mutations = { const newStatus = state.allStatusesObject[status.id] newStatus.deleted = true }, + setManyDeleted (state, condition) { + Object.values(state.allStatusesObject).forEach(status => { + if (condition(status)) { + status.deleted = true + } + }) + }, setLoading (state, { timeline, value }) { state.timelines[timeline].loading = value }, @@ -438,6 +445,9 @@ const statuses = { commit('setDeleted', { status }) apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials }) }, + markStatusesAsDeleted ({ commit }, condition) { + commit('setManyDeleted', condition) + }, favorite ({ rootState, commit }, status) { // Optimistic favoriting... commit('setFavorited', { status, value: true }) diff --git a/src/modules/users.js b/src/modules/users.js index 1a507d31..5839574b 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -37,6 +37,28 @@ export const mutations = { const user = state.usersObject[id] set(user, 'muted', muted) }, + tagUser (state, { user: { id }, tag }) { + const user = state.usersObject[id] + const tags = user.tags || [] + const newTags = tags.concat([tag]) + set(user, 'tags', newTags) + }, + untagUser (state, { user: { id }, tag }) { + const user = state.usersObject[id] + const tags = user.tags || [] + const newTags = tags.filter(t => t !== tag) + set(user, 'tags', newTags) + }, + updateRight (state, { user: { id }, right, value }) { + const user = state.usersObject[id] + let newRights = user.rights + newRights[right] = value + set(user, 'rights', newRights) + }, + updateActivationStatus (state, { user: { id }, status }) { + const user = state.usersObject[id] + set(user, 'deactivated', !status) + }, setCurrentUser (state, user) { state.lastLoginName = user.screen_name state.currentUser = merge(state.currentUser || {}, user) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 030c2f5e..bd331062 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -16,6 +16,10 @@ const CHANGE_PASSWORD_URL = '/api/pleroma/change_password' const FOLLOW_REQUESTS_URL = '/api/pleroma/friend_requests' const APPROVE_USER_URL = '/api/pleroma/friendships/approve' const DENY_USER_URL = '/api/pleroma/friendships/deny' +const TAG_USER_URL = '/api/pleroma/admin/users/tag' +const PERMISSION_GROUP_URL = '/api/pleroma/admin/permission_group' +const ACTIVATION_STATUS_URL = '/api/pleroma/admin/activation_status' +const ADMIN_USER_URL = '/api/pleroma/admin/user' const SUGGESTIONS_URL = '/api/v1/suggestions' const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites' @@ -352,6 +356,86 @@ const fetchStatus = ({id, credentials}) => { .then((data) => parseStatus(data)) } +const tagUser = ({tag, credentials, ...options}) => { + const screenName = options.screen_name + const form = { + nicknames: [screenName], + tags: [tag] + } + + const headers = authHeaders(credentials) + headers['Content-Type'] = 'application/json' + + return fetch(TAG_USER_URL, { + method: 'PUT', + headers: headers, + body: JSON.stringify(form) + }) +} + +const untagUser = ({tag, credentials, ...options}) => { + const screenName = options.screen_name + const body = { + nicknames: [screenName], + tags: [tag] + } + + const headers = authHeaders(credentials) + headers['Content-Type'] = 'application/json' + + return fetch(TAG_USER_URL, { + method: 'DELETE', + headers: headers, + body: JSON.stringify(body) + }) +} + +const addRight = ({right, credentials, ...user}) => { + const screenName = user.screen_name + + return fetch(`${PERMISSION_GROUP_URL}/${screenName}/${right}`, { + method: 'POST', + headers: authHeaders(credentials), + body: {} + }) +} + +const deleteRight = ({right, credentials, ...user}) => { + const screenName = user.screen_name + + return fetch(`${PERMISSION_GROUP_URL}/${screenName}/${right}`, { + method: 'DELETE', + headers: authHeaders(credentials), + body: {} + }) +} + +const setActivationStatus = ({status, credentials, ...user}) => { + const screenName = user.screen_name + const body = { + status: status + } + + const headers = authHeaders(credentials) + headers['Content-Type'] = 'application/json' + + return fetch(`${ACTIVATION_STATUS_URL}/${screenName}.json`, { + method: 'PUT', + headers: headers, + body: JSON.stringify(body) + }) +} + +const deleteUser = ({credentials, ...user}) => { + const screenName = user.screen_name + const headers = authHeaders(credentials) + + return fetch(`${ADMIN_USER_URL}.json?nickname=${screenName}`, { + method: 'DELETE', + headers: headers + }) +} + const fetchTimeline = ({timeline, credentials, since = false, until = false, userId = false, tag = false, withMuted = false}) => { const timelineUrls = { public: MASTODON_PUBLIC_TIMELINE, @@ -666,6 +750,12 @@ const apiService = { fetchBlocks, fetchOAuthTokens, revokeOAuthToken, + tagUser, + untagUser, + deleteUser, + addRight, + deleteRight, + setActivationStatus, register, getCaptcha, updateAvatar, diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 71e78d2f..badcbb06 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -62,6 +62,30 @@ const backendInteractorService = (credentials) => { return timelineFetcherService.startFetching({timeline, store, credentials, userId, tag}) } + const tagUser = ({screen_name}, tag) => { + return apiService.tagUser({screen_name, tag, credentials}) + } + + const untagUser = ({screen_name}, tag) => { + return apiService.untagUser({screen_name, tag, credentials}) + } + + const addRight = ({screen_name}, right) => { + return apiService.addRight({screen_name, right, credentials}) + } + + const deleteRight = ({screen_name}, right) => { + return apiService.deleteRight({screen_name, right, credentials}) + } + + const setActivationStatus = ({screen_name}, status) => { + return apiService.setActivationStatus({screen_name, status, credentials}) + } + + const deleteUser = ({screen_name}) => { + return apiService.deleteUser({screen_name, credentials}) + } + const fetchMutes = () => apiService.fetchMutes({credentials}) const muteUser = (id) => apiService.muteUser({credentials, id}) const unmuteUser = (id) => apiService.unmuteUser({credentials, id}) @@ -104,6 +128,12 @@ const backendInteractorService = (credentials) => { fetchBlocks, fetchOAuthTokens, revokeOAuthToken, + tagUser, + untagUser, + addRight, + deleteRight, + deleteUser, + setActivationStatus, register, getCaptcha, updateAvatar, diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index ea57e6b2..8aa4b352 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -67,6 +67,11 @@ export const parseUser = (data) => { output.statusnet_blocking = relationship.blocking output.muted = relationship.muting } + + output.rights = { + moderator: data.pleroma.is_moderator, + admin: data.pleroma.is_admin + } } // Missing, trying to recover @@ -103,7 +108,12 @@ export const parseUser = (data) => { // QVITTER ONLY FOR NOW // Really only applies to logged in user, really.. I THINK - output.rights = data.rights + if (data.rights) { + output.rights = { + moderator: data.rights.delete_others_notice, + admin: data.rights.admin + } + } output.no_rich_text = data.no_rich_text output.default_scope = data.default_scope output.hide_follows = data.hide_follows @@ -125,6 +135,13 @@ export const parseUser = (data) => { output.follow_request_count = data.pleroma.follow_request_count } + if (data.pleroma) { + output.tags = data.pleroma.tags + output.deactivated = data.pleroma.deactivated + } + + output.tags = output.tags || [] + return output } diff --git a/yarn.lock b/yarn.lock index 0fe45479..58007622 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4831,6 +4831,10 @@ pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +popper.js@^1.14.7: + version "1.14.7" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -6457,6 +6461,12 @@ vue-loader@^11.1.0: vue-style-loader "^2.0.0" vue-template-es2015-compiler "^1.2.2" +vue-popperjs@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vue-popperjs/-/vue-popperjs-2.0.3.tgz#7c446d0ba7c63170ccb33a02669d0df4efc3d8cd" + dependencies: + popper.js "^1.14.7" + vue-router@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.2.tgz#dedc67afe6c4e2bc25682c8b1c2a8c0d7c7e56be" From c9a9b3122db9c2c089e36930ed2a252f80de71cd Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 2 Apr 2019 10:26:14 -0400 Subject: [PATCH 02/14] #469 - DM warning text should vary based on BE setting --- src/boot/after_store.js | 3 ++- src/components/post_status_form/post_status_form.js | 4 ++++ src/components/post_status_form/post_status_form.vue | 2 +- src/modules/instance.js | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 862a534d..f2c1aa0f 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -9,12 +9,13 @@ const getStatusnetConfig = async ({ store }) => { const res = await window.fetch('/api/statusnet/config.json') if (res.ok) { const data = await res.json() - const { name, closed: registrationClosed, textlimit, uploadlimit, server, vapidPublicKey } = data.site + const { name, closed: registrationClosed, textlimit, uploadlimit, server, vapidPublicKey, safeDMMentionsEnabled } = data.site store.dispatch('setInstanceOption', { name: 'name', value: name }) store.dispatch('setInstanceOption', { name: 'registrationOpen', value: (registrationClosed === '0') }) store.dispatch('setInstanceOption', { name: 'textlimit', value: parseInt(textlimit) }) store.dispatch('setInstanceOption', { name: 'server', value: server }) + store.dispatch('setInstanceOption', { name: 'safeDM', value: safeDMMentionsEnabled !== '0' }) // TODO: default values for this stuff, added if to not make it break on // my dev config out of the box. diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index 40e2610e..d52abeee 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -179,6 +179,10 @@ const PostStatusForm = { }, postFormats () { return this.$store.state.instance.postFormats || [] + }, + showDirectWarning () { + console.log(this.$store.state.instance) + return this.$store.state.instance.safeDM && this.newStatus.visibility === 'direct' } }, methods: { diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index 3d3a1082..2f70a2ad 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -9,7 +9,7 @@ class="visibility-notice"> {{ $t('post_status.account_not_locked_warning_link') }} -

{{ $t('post_status.direct_warning') }}

+

{{ $t('post_status.direct_warning') }}

Date: Tue, 2 Apr 2019 10:28:38 -0400 Subject: [PATCH 03/14] #469 - clean up --- src/components/post_status_form/post_status_form.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index d52abeee..e0bb191c 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -181,7 +181,6 @@ const PostStatusForm = { return this.$store.state.instance.postFormats || [] }, showDirectWarning () { - console.log(this.$store.state.instance) return this.$store.state.instance.safeDM && this.newStatus.visibility === 'direct' } }, From 67258571c59c9e037d121b807f0a75c26e612c01 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 2 Apr 2019 11:19:45 -0400 Subject: [PATCH 04/14] #469 - update behavior of safe_dm --- src/components/post_status_form/post_status_form.js | 4 ++-- src/components/post_status_form/post_status_form.vue | 7 +++++-- src/i18n/en.json | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index e0bb191c..c65c27e2 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -180,8 +180,8 @@ const PostStatusForm = { postFormats () { return this.$store.state.instance.postFormats || [] }, - showDirectWarning () { - return this.$store.state.instance.safeDM && this.newStatus.visibility === 'direct' + safeDMEnabled () { + return this.$store.state.instance.safeDM } }, methods: { diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index 2f70a2ad..1ce2b647 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -3,13 +3,16 @@
{{ $t('post_status.account_not_locked_warning_link') }} -

{{ $t('post_status.direct_warning') }}

+

+ {{ $t('post_status.direct_warning_to_first_only') }} + {{ $t('post_status.direct_warning_to_all') }} +

Date: Tue, 2 Apr 2019 12:46:22 -0400 Subject: [PATCH 05/14] #469 - update text copy --- src/i18n/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/en.json b/src/i18n/en.json index 0ce751bb..1e82cd0a 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -81,7 +81,7 @@ "content_warning": "Subject (optional)", "default": "Just landed in L.A.", "direct_warning_to_all": "This post will be visible to all the mentioned users.", - "direct_warning_to_first_only": "This post will only be visible to the mentioned user at the beginning of the message.", + "direct_warning_to_first_only": "This post will only be visible to the mentioned users at the beginning of the message.", "posting": "Posting", "scope": { "direct": "Direct - Post to mentioned users only", From ea27483f2728b5c2f1dd57228b8bf1ab9ae223ff Mon Sep 17 00:00:00 2001 From: jasper Date: Wed, 3 Apr 2019 09:04:46 -0700 Subject: [PATCH 06/14] Fix notification bugs --- src/components/notifications/notifications.js | 7 --- src/modules/statuses.js | 43 +++++++++++-------- src/modules/users.js | 6 ++- .../backend_interactor_service.js | 2 + 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index d3db4b29..d9ce7604 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -10,13 +10,6 @@ const Notifications = { props: [ 'noHeading' ], - created () { - const store = this.$store - const credentials = store.state.users.currentUser.credentials - - const fetcherId = notificationsFetcher.startFetching({ store, credentials }) - this.$store.commit('setNotificationFetcher', { fetcherId }) - }, data () { return { bottomedOut: false diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 8e0203e3..660d5c26 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -20,20 +20,22 @@ const emptyTl = (userId = 0) => ({ flushMarker: 0 }) +const emptyNotifications = () => ({ + desktopNotificationSilence: true, + maxId: 0, + minId: Number.POSITIVE_INFINITY, + data: [], + idStore: {}, + loading: false, + error: false, + fetcherId: null +}) + export const defaultState = () => ({ allStatuses: [], allStatusesObject: {}, maxId: 0, - notifications: { - desktopNotificationSilence: true, - maxId: 0, - minId: Number.POSITIVE_INFINITY, - data: [], - idStore: {}, - loading: false, - error: false, - fetcherId: null - }, + notifications: emptyNotifications(), favorites: new Set(), error: false, timelines: { @@ -340,9 +342,9 @@ export const mutations = { oldTimeline.visibleStatusesObject = {} each(oldTimeline.visibleStatuses, (status) => { oldTimeline.visibleStatusesObject[status.id] = status }) }, - setNotificationFetcher (state, { fetcherId }) { - state.notifications.fetcherId = fetcherId - }, + // setNotificationFetcher (state, { fetcherId }) { + // state.notifications.fetcherId = fetcherId + // }, resetStatuses (state) { const emptyState = defaultState() Object.entries(emptyState).forEach(([key, value]) => { @@ -352,6 +354,9 @@ export const mutations = { clearTimeline (state, { timeline }) { state.timelines[timeline] = emptyTl(state.timelines[timeline].userId) }, + clearNotifications (state) { + state.notifications = emptyNotifications() + }, setFavorited (state, { status, value }) { const newStatus = state.allStatusesObject[status.id] newStatus.favorited = value @@ -428,12 +433,12 @@ const statuses = { setNotificationsSilence ({ rootState, commit }, { value }) { commit('setNotificationsSilence', { value }) }, - stopFetchingNotifications ({ rootState, commit }) { - if (rootState.statuses.notifications.fetcherId) { - window.clearInterval(rootState.statuses.notifications.fetcherId) - } - commit('setNotificationFetcher', { fetcherId: null }) - }, + // stopFetchingNotifications ({ rootState, commit }) { + // if (rootState.statuses.notifications.fetcherId) { + // window.clearInterval(rootState.statuses.notifications.fetcherId) + // } + // commit('setNotificationFetcher', { fetcherId: null }) + // }, deleteStatus ({ rootState, commit }, status) { commit('setDeleted', { status }) apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials }) diff --git a/src/modules/users.js b/src/modules/users.js index 1a507d31..3cfae1fc 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -331,7 +331,8 @@ const users = { store.commit('setToken', false) store.dispatch('stopFetching', 'friends') store.commit('setBackendInteractor', backendInteractorService()) - store.dispatch('stopFetchingNotifications') + store.dispatch('stopFetching', 'notifications') + store.commit('clearNotifications') store.commit('resetStatuses') }, loginUser (store, accessToken) { @@ -365,6 +366,9 @@ const users = { // Start getting fresh posts. store.dispatch('startFetching', { timeline: 'friends' }) + // Start fetching notifications + store.dispatch('startFetching', { timeline: 'notifications' }) + // Get user mutes store.dispatch('fetchMutes') diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 71e78d2f..f28686f8 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -1,5 +1,6 @@ import apiService from '../api/api.service.js' import timelineFetcherService from '../timeline_fetcher/timeline_fetcher.service.js' +import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js' const backendInteractorService = (credentials) => { const fetchStatus = ({id}) => { @@ -59,6 +60,7 @@ const backendInteractorService = (credentials) => { } const startFetching = ({timeline, store, userId = false, tag}) => { + if (timeline === 'notifications') { return notificationsFetcher.startFetching({store, credentials}) } return timelineFetcherService.startFetching({timeline, store, credentials, userId, tag}) } From 7c2b65e9a3645d0c6f8bd88abe6f10ff6b016a9c Mon Sep 17 00:00:00 2001 From: jasper Date: Wed, 3 Apr 2019 09:08:23 -0700 Subject: [PATCH 07/14] Remove useless codes --- src/modules/statuses.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 660d5c26..8e58d673 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -27,8 +27,7 @@ const emptyNotifications = () => ({ data: [], idStore: {}, loading: false, - error: false, - fetcherId: null + error: false }) export const defaultState = () => ({ @@ -342,9 +341,6 @@ export const mutations = { oldTimeline.visibleStatusesObject = {} each(oldTimeline.visibleStatuses, (status) => { oldTimeline.visibleStatusesObject[status.id] = status }) }, - // setNotificationFetcher (state, { fetcherId }) { - // state.notifications.fetcherId = fetcherId - // }, resetStatuses (state) { const emptyState = defaultState() Object.entries(emptyState).forEach(([key, value]) => { @@ -433,12 +429,6 @@ const statuses = { setNotificationsSilence ({ rootState, commit }, { value }) { commit('setNotificationsSilence', { value }) }, - // stopFetchingNotifications ({ rootState, commit }) { - // if (rootState.statuses.notifications.fetcherId) { - // window.clearInterval(rootState.statuses.notifications.fetcherId) - // } - // commit('setNotificationFetcher', { fetcherId: null }) - // }, deleteStatus ({ rootState, commit }, status) { commit('setDeleted', { status }) apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials }) From a1275be4c0c83dc848e402bb631990d0cb27bb8c Mon Sep 17 00:00:00 2001 From: jasper Date: Thu, 4 Apr 2019 09:03:56 -0700 Subject: [PATCH 08/14] Separate timeline and notification --- .../public_and_external_timeline.js | 2 +- .../public_timeline/public_timeline.js | 2 +- src/components/tag_timeline/tag_timeline.js | 4 +-- src/components/user_profile/user_profile.js | 6 ++--- src/modules/api.js | 27 ++++++++++++------- src/modules/users.js | 4 +-- .../backend_interactor_service.js | 12 ++++++--- 7 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.js b/src/components/public_and_external_timeline/public_and_external_timeline.js index d45677e0..f614c13b 100644 --- a/src/components/public_and_external_timeline/public_and_external_timeline.js +++ b/src/components/public_and_external_timeline/public_and_external_timeline.js @@ -7,7 +7,7 @@ const PublicAndExternalTimeline = { timeline () { return this.$store.state.statuses.timelines.publicAndExternal } }, created () { - this.$store.dispatch('startFetching', { timeline: 'publicAndExternal' }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' }) }, destroyed () { this.$store.dispatch('stopFetching', 'publicAndExternal') diff --git a/src/components/public_timeline/public_timeline.js b/src/components/public_timeline/public_timeline.js index 64c951ac..8976a99c 100644 --- a/src/components/public_timeline/public_timeline.js +++ b/src/components/public_timeline/public_timeline.js @@ -7,7 +7,7 @@ const PublicTimeline = { timeline () { return this.$store.state.statuses.timelines.public } }, created () { - this.$store.dispatch('startFetching', { timeline: 'public' }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'public' }) }, destroyed () { this.$store.dispatch('stopFetching', 'public') diff --git a/src/components/tag_timeline/tag_timeline.js b/src/components/tag_timeline/tag_timeline.js index 41b09706..458eb1c5 100644 --- a/src/components/tag_timeline/tag_timeline.js +++ b/src/components/tag_timeline/tag_timeline.js @@ -3,7 +3,7 @@ import Timeline from '../timeline/timeline.vue' const TagTimeline = { created () { this.$store.commit('clearTimeline', { timeline: 'tag' }) - this.$store.dispatch('startFetching', { timeline: 'tag', tag: this.tag }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'tag', tag: this.tag }) }, components: { Timeline @@ -15,7 +15,7 @@ const TagTimeline = { watch: { tag () { this.$store.commit('clearTimeline', { timeline: 'tag' }) - this.$store.dispatch('startFetching', { timeline: 'tag', tag: this.tag }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'tag', tag: this.tag }) } }, destroyed () { diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 1df06fe6..bac729c0 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -90,7 +90,7 @@ const UserProfile = { methods: { startFetchFavorites () { if (this.isUs) { - this.$store.dispatch('startFetching', { timeline: 'favorites', userId: this.userId }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId: this.userId }) } }, fetchUserId () { @@ -118,8 +118,8 @@ const UserProfile = { }, startUp () { if (this.userId) { - this.$store.dispatch('startFetching', { timeline: 'user', userId: this.userId }) - this.$store.dispatch('startFetching', { timeline: 'media', userId: this.userId }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'user', userId: this.userId }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'media', userId: this.userId }) this.startFetchFavorites() } }, diff --git a/src/modules/api.js b/src/modules/api.js index 31cb55c6..6242dfa1 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -13,11 +13,11 @@ const api = { setBackendInteractor (state, backendInteractor) { state.backendInteractor = backendInteractor }, - addFetcher (state, {timeline, fetcher}) { - state.fetchers[timeline] = fetcher + addFetcher (state, {fetcherName, fetcher}) { + state.fetchers[fetcherName] = fetcher }, - removeFetcher (state, {timeline}) { - delete state.fetchers[timeline] + removeFetcher (state, { fetcherName }) { + delete state.fetchers[fetcherName] }, setWsToken (state, token) { state.wsToken = token @@ -33,17 +33,24 @@ const api = { } }, actions: { - startFetching (store, {timeline = 'friends', tag = false, userId = false}) { + startFetchingTimeline (store, {timeline = 'friends', tag = false, userId = false}) { // Don't start fetching if we already are. if (store.state.fetchers[timeline]) return - const fetcher = store.state.backendInteractor.startFetching({ timeline, store, userId, tag }) - store.commit('addFetcher', { timeline, fetcher }) + const fetcher = store.state.backendInteractor.startFetchingTimeline({ timeline, store, userId, tag }) + store.commit('addFetcher', { fetcherName: timeline, fetcher }) }, - stopFetching (store, timeline) { - const fetcher = store.state.fetchers[timeline] + startFetchingNotifications (store) { + // Don't start fetching if we already are. + if (store.state.fetchers['notifications']) return + + const fetcher = store.state.backendInteractor.startFetchingNotifications({ store }) + store.commit('addFetcher', { fetcherName: 'notifications', fetcher }) + }, + stopFetching (store, fetcherName) { + const fetcher = store.state.fetchers[fetcherName] window.clearInterval(fetcher) - store.commit('removeFetcher', {timeline}) + store.commit('removeFetcher', { fetcherName }) }, setWsToken (store, token) { store.commit('setWsToken', token) diff --git a/src/modules/users.js b/src/modules/users.js index 3cfae1fc..b0c7f2f6 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -364,10 +364,10 @@ const users = { } // Start getting fresh posts. - store.dispatch('startFetching', { timeline: 'friends' }) + store.dispatch('startFetchingTimeline', { timeline: 'friends' }) // Start fetching notifications - store.dispatch('startFetching', { timeline: 'notifications' }) + store.dispatch('startFetchingNotifications') // Get user mutes store.dispatch('fetchMutes') diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index f28686f8..7dd139c6 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -59,9 +59,12 @@ const backendInteractorService = (credentials) => { return apiService.denyUser({credentials, id}) } - const startFetching = ({timeline, store, userId = false, tag}) => { - if (timeline === 'notifications') { return notificationsFetcher.startFetching({store, credentials}) } - return timelineFetcherService.startFetching({timeline, store, credentials, userId, tag}) + const startFetchingTimeline = ({ timeline, store, userId = false, tag }) => { + return timelineFetcherService.startFetching({ timeline, store, credentials, userId, tag }) + } + + const startFetchingNotifications = ({ store }) => { + return notificationsFetcher.startFetching({ store, credentials }) } const fetchMutes = () => apiService.fetchMutes({credentials}) @@ -99,7 +102,8 @@ const backendInteractorService = (credentials) => { fetchUserRelationship, fetchAllFollowing, verifyCredentials: apiService.verifyCredentials, - startFetching, + startFetchingTimeline, + startFetchingNotifications, fetchMutes, muteUser, unmuteUser, From 1c04cd2036cb93e8a9f1729d26004719331e31dd Mon Sep 17 00:00:00 2001 From: jasper Date: Thu, 4 Apr 2019 09:06:53 -0700 Subject: [PATCH 09/14] Add space --- src/modules/api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/api.js b/src/modules/api.js index 6242dfa1..7ed3edac 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -13,7 +13,7 @@ const api = { setBackendInteractor (state, backendInteractor) { state.backendInteractor = backendInteractor }, - addFetcher (state, {fetcherName, fetcher}) { + addFetcher (state, { fetcherName, fetcher }) { state.fetchers[fetcherName] = fetcher }, removeFetcher (state, { fetcherName }) { @@ -33,7 +33,7 @@ const api = { } }, actions: { - startFetchingTimeline (store, {timeline = 'friends', tag = false, userId = false}) { + startFetchingTimeline (store, { timeline = 'friends', tag = false, userId = false }) { // Don't start fetching if we already are. if (store.state.fetchers[timeline]) return From 7259e02a10c1a4b0156dbc401c486e0fa6382d71 Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 8 Apr 2019 16:49:51 +0000 Subject: [PATCH 10/14] remove debug message --- src/modules/interface.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/interface.js b/src/modules/interface.js index 71554787..5b2762e5 100644 --- a/src/modules/interface.js +++ b/src/modules/interface.js @@ -48,7 +48,6 @@ const interfaceMod = { commit('setNotificationPermission', permission) }, setMobileLayout ({ commit }, value) { - console.log('setMobileLayout called') commit('setMobileLayout', value) } } From 1570e779b1a3497f29e0681f1390322e8e65030b Mon Sep 17 00:00:00 2001 From: jasper Date: Tue, 9 Apr 2019 08:38:13 -0700 Subject: [PATCH 11/14] Prevent repeated fetching --- src/components/timeline/timeline.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js index 1da7d5cc..19d9a9ac 100644 --- a/src/components/timeline/timeline.js +++ b/src/components/timeline/timeline.js @@ -52,7 +52,7 @@ const Timeline = { window.addEventListener('scroll', this.scrollLoad) - if (this.timelineName === 'friends' && !credentials) { return false } + if (store.state.api.fetchers[this.timelineName]) { return false } timelineFetcher.fetchAndUpdate({ store, From b7d7c216177407e451bbab4a6178016dcd7b805d Mon Sep 17 00:00:00 2001 From: jasper Date: Tue, 9 Apr 2019 08:57:41 -0700 Subject: [PATCH 12/14] Add await to login befor redirect to friends timeline --- src/components/login_form/login_form.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index fb6dc651..e0fbb329 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -31,14 +31,18 @@ const LoginForm = { username: this.user.username, password: this.user.password } - ).then((result) => { + ).then(async (result) => { if (result.error) { this.authError = result.error this.user.password = '' return } this.$store.commit('setToken', result.access_token) - this.$store.dispatch('loginUser', result.access_token) + try { + await this.$store.dispatch('loginUser', result.access_token) + } catch (e) { + console.log(e) + } this.$router.push({name: 'friends'}) }) }) From 011f04c196318e25cfff10f3fa41321070511919 Mon Sep 17 00:00:00 2001 From: jasper Date: Tue, 9 Apr 2019 09:19:48 -0700 Subject: [PATCH 13/14] fix small bug --- src/components/login_form/login_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index e0fbb329..dc917e47 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -40,10 +40,10 @@ const LoginForm = { this.$store.commit('setToken', result.access_token) try { await this.$store.dispatch('loginUser', result.access_token) + this.$router.push({name: 'friends'}) } catch (e) { console.log(e) } - this.$router.push({name: 'friends'}) }) }) }, From 5df049ca3148c1bdf29a5f3ee1a60b7ecf94bb88 Mon Sep 17 00:00:00 2001 From: jared Date: Tue, 9 Apr 2019 14:10:51 -0400 Subject: [PATCH 14/14] #486 - remove expand button on conversation page --- src/components/conversation/conversation.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index c39a3ed9..c3bbb597 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -13,7 +13,7 @@ :key="status.id" :inlineExpanded="collapsable" :statusoid="status" - :expandable='!expanded' + :expandable='!isExpanded' :focused="focused(status.id)" :inConversation="isExpanded" :highlight="getHighlight()"