diff --git a/package.json b/package.json
index 43907f3e..30a317b2 100644
--- a/package.json
+++ b/package.json
@@ -24,11 +24,13 @@
"localforage": "^1.5.0",
"object-path": "^0.11.3",
"phoenix": "^1.3.0",
+ "popper.js": "^1.14.7",
"sanitize-html": "^1.13.0",
+ "v-click-outside": "^2.1.1",
"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 f2c1aa0f..603de348 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -171,9 +171,10 @@ const getCustomEmoji = async ({ store }) => {
try {
const res = await window.fetch('/api/pleroma/emoji.json')
if (res.ok) {
- const values = await res.json()
+ const result = await res.json()
+ const values = Array.isArray(result) ? Object.assign({}, ...result) : result
const emoji = Object.keys(values).map((key) => {
- return { shortcode: key, image_url: values[key] }
+ return { shortcode: key, image_url: values[key].image_url || values[key] }
})
store.dispatch('setInstanceOption', { name: 'customEmoji', value: emoji })
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: true })
@@ -211,6 +212,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/autosuggest/autosuggest.js b/src/components/autosuggest/autosuggest.js
new file mode 100644
index 00000000..d4efe912
--- /dev/null
+++ b/src/components/autosuggest/autosuggest.js
@@ -0,0 +1,52 @@
+const debounceMilliseconds = 500
+
+export default {
+ props: {
+ query: { // function to query results and return a promise
+ type: Function,
+ required: true
+ },
+ filter: { // function to filter results in real time
+ type: Function
+ },
+ placeholder: {
+ type: String,
+ default: 'Search...'
+ }
+ },
+ data () {
+ return {
+ term: '',
+ timeout: null,
+ results: [],
+ resultsVisible: false
+ }
+ },
+ computed: {
+ filtered () {
+ return this.filter ? this.filter(this.results) : this.results
+ }
+ },
+ watch: {
+ term (val) {
+ this.fetchResults(val)
+ }
+ },
+ methods: {
+ fetchResults (term) {
+ clearTimeout(this.timeout)
+ this.timeout = setTimeout(() => {
+ this.results = []
+ if (term) {
+ this.query(term).then((results) => { this.results = results })
+ }
+ }, debounceMilliseconds)
+ },
+ onInputClick () {
+ this.resultsVisible = true
+ },
+ onClickOutside () {
+ this.resultsVisible = false
+ }
+ }
+}
diff --git a/src/components/autosuggest/autosuggest.vue b/src/components/autosuggest/autosuggest.vue
new file mode 100644
index 00000000..91657a2d
--- /dev/null
+++ b/src/components/autosuggest/autosuggest.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue
index 8afe8b44..48de6678 100644
--- a/src/components/basic_user_card/basic_user_card.vue
+++ b/src/components/basic_user_card/basic_user_card.vue
@@ -24,19 +24,11 @@
diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index 69058bf6..30600f73 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -1,5 +1,4 @@
-import { reduce, filter, findIndex } from 'lodash'
-import { set } from 'vue'
+import { reduce, filter, findIndex, clone } from 'lodash'
import Status from '../status/status.vue'
const sortById = (a, b) => {
@@ -36,8 +35,7 @@ const conversation = {
data () {
return {
highlight: null,
- expanded: false,
- converationStatusIds: []
+ expanded: false
}
},
props: [
@@ -54,15 +52,6 @@ const conversation = {
status () {
return this.statusoid
},
- idsToShow () {
- if (this.converationStatusIds.length > 0) {
- return this.converationStatusIds
- } else if (this.statusId) {
- return [this.statusId]
- } else {
- return []
- }
- },
statusId () {
if (this.statusoid.retweeted_status) {
return this.statusoid.retweeted_status.id
@@ -70,6 +59,13 @@ const conversation = {
return this.statusoid.id
}
},
+ conversationId () {
+ if (this.statusoid.retweeted_status) {
+ return this.statusoid.retweeted_status.statusnet_conversation_id
+ } else {
+ return this.statusoid.statusnet_conversation_id
+ }
+ },
conversation () {
if (!this.status) {
return []
@@ -79,12 +75,7 @@ const conversation = {
return [this.status]
}
- const statusesObject = this.$store.state.statuses.allStatusesObject
- const conversation = this.idsToShow.reduce((acc, id) => {
- acc.push(statusesObject[id])
- return acc
- }, [])
-
+ const conversation = clone(this.$store.state.statuses.conversationsObject[this.conversationId])
const statusIndex = findIndex(conversation, { id: this.statusId })
if (statusIndex !== -1) {
conversation[statusIndex] = this.status
@@ -131,10 +122,6 @@ const conversation = {
.then(({ancestors, descendants}) => {
this.$store.dispatch('addNewStatuses', { statuses: ancestors })
this.$store.dispatch('addNewStatuses', { statuses: descendants })
- set(this, 'converationStatusIds', [].concat(
- ancestors.map(_ => _.id).filter(_ => _ !== this.statusId),
- this.statusId,
- descendants.map(_ => _.id).filter(_ => _ !== this.statusId)))
})
.then(() => this.setHighlight(this.statusId))
} else {
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()"
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/follow_card/follow_card.js b/src/components/follow_card/follow_card.js
index ac4e265a..dc4a0d41 100644
--- a/src/components/follow_card/follow_card.js
+++ b/src/components/follow_card/follow_card.js
@@ -10,8 +10,7 @@ const FollowCard = {
data () {
return {
inProgress: false,
- requestSent: false,
- updated: false
+ requestSent: false
}
},
components: {
@@ -19,10 +18,8 @@ const FollowCard = {
RemoteFollow
},
computed: {
- isMe () { return this.$store.state.users.currentUser.id === this.user.id },
- following () { return this.updated ? this.updated.following : this.user.following },
- showFollow () {
- return !this.following || this.updated && !this.updated.following
+ isMe () {
+ return this.$store.state.users.currentUser.id === this.user.id
},
loggedIn () {
return this.$store.state.users.currentUser
@@ -31,17 +28,15 @@ const FollowCard = {
methods: {
followUser () {
this.inProgress = true
- requestFollow(this.user, this.$store).then(({ sent, updated }) => {
+ requestFollow(this.user, this.$store).then(({ sent }) => {
this.inProgress = false
this.requestSent = sent
- this.updated = updated
})
},
unfollowUser () {
this.inProgress = true
- requestUnfollow(this.user, this.$store).then(({ updated }) => {
+ requestUnfollow(this.user, this.$store).then(() => {
this.inProgress = false
- this.updated = updated
})
}
}
diff --git a/src/components/follow_card/follow_card.vue b/src/components/follow_card/follow_card.vue
index 9f314fd3..94e2836f 100644
--- a/src/components/follow_card/follow_card.vue
+++ b/src/components/follow_card/follow_card.vue
@@ -4,34 +4,38 @@
{{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }}
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/src/components/follow_requests/follow_requests.vue b/src/components/follow_requests/follow_requests.vue
index b83c2d68..36901fb4 100644
--- a/src/components/follow_requests/follow_requests.vue
+++ b/src/components/follow_requests/follow_requests.vue
@@ -4,7 +4,7 @@
{{$t('nav.friend_requests')}}
-
+
diff --git a/src/components/list/list.vue b/src/components/list/list.vue
new file mode 100644
index 00000000..7136915b
--- /dev/null
+++ b/src/components/list/list.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js
index fb6dc651..dc917e47 100644
--- a/src/components/login_form/login_form.js
+++ b/src/components/login_form/login_form.js
@@ -31,15 +31,19 @@ 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)
- this.$router.push({name: 'friends'})
+ try {
+ await this.$store.dispatch('loginUser', result.access_token)
+ this.$router.push({name: 'friends'})
+ } catch (e) {
+ console.log(e)
+ }
})
})
},
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 @@
+
+
+
+
+
+
+
+
+
+ {{ $t('user_card.admin_menu.delete_user') }}
+ {{ $t('user_card.admin_menu.delete_user_confirmation') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index 42a48f3f..e59e7497 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -21,25 +21,28 @@ 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.from_profile.id]
}
},
computed: {
userClass () {
- return highlightClass(this.notification.action.user)
+ return highlightClass(this.notification.from_profile)
},
userStyle () {
const highlight = this.$store.state.config.highlight
- const user = this.notification.action.user
+ const user = this.notification.from_profile
return highlightStyle(highlight[user.screen_name])
},
userInStore () {
- return this.$store.getters.findUser(this.notification.action.user.id)
+ return this.$store.getters.findUser(this.notification.from_profile.id)
},
user () {
if (this.userInStore) {
return this.userInStore
}
- return {}
+ return this.notification.from_profile
}
}
}
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 8f532747..ae11d692 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -1,15 +1,20 @@
-
+
+
-
-
+
+
-
+
-
- {{ notification.action.user.name }}
+
+ {{ notification.from_profile.name }}
{{$t('notifications.favorited_you')}}
@@ -23,19 +28,24 @@
{{$t('notifications.followed_you')}}
-
+
+
+
+
+
+
-
+
-
- @{{notification.action.user.screen_name}}
+
+ @{{notification.from_profile.screen_name}}
-
+
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index d3db4b29..e341212e 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
@@ -56,7 +49,7 @@ const Notifications = {
},
methods: {
markAsSeen () {
- this.$store.dispatch('markNotificationsAsSeen', this.visibleNotifications)
+ this.$store.dispatch('markNotificationsAsSeen')
},
fetchOlderNotifications () {
const store = this.$store
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 634a03ac..88775be1 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -12,7 +12,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/progress_button/progress_button.vue b/src/components/progress_button/progress_button.vue
new file mode 100644
index 00000000..737360bb
--- /dev/null
+++ b/src/components/progress_button/progress_button.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
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/selectable_list/selectable_list.js b/src/components/selectable_list/selectable_list.js
new file mode 100644
index 00000000..10980d46
--- /dev/null
+++ b/src/components/selectable_list/selectable_list.js
@@ -0,0 +1,66 @@
+import List from '../list/list.vue'
+import Checkbox from '../checkbox/checkbox.vue'
+
+const SelectableList = {
+ components: {
+ List,
+ Checkbox
+ },
+ props: {
+ items: {
+ type: Array,
+ default: () => []
+ },
+ getKey: {
+ type: Function,
+ default: item => item.id
+ }
+ },
+ data () {
+ return {
+ selected: []
+ }
+ },
+ computed: {
+ allKeys () {
+ return this.items.map(this.getKey)
+ },
+ filteredSelected () {
+ return this.allKeys.filter(key => this.selected.indexOf(key) !== -1)
+ },
+ allSelected () {
+ return this.filteredSelected.length === this.items.length
+ },
+ noneSelected () {
+ return this.filteredSelected.length === 0
+ },
+ someSelected () {
+ return !this.allSelected && !this.noneSelected
+ }
+ },
+ methods: {
+ isSelected (item) {
+ return this.filteredSelected.indexOf(this.getKey(item)) !== -1
+ },
+ toggle (checked, item) {
+ const key = this.getKey(item)
+ const oldChecked = this.isSelected(key)
+ if (checked !== oldChecked) {
+ if (checked) {
+ this.selected.push(key)
+ } else {
+ this.selected.splice(this.selected.indexOf(key), 1)
+ }
+ }
+ },
+ toggleAll (value) {
+ if (value) {
+ this.selected = this.allKeys.slice(0)
+ } else {
+ this.selected = []
+ }
+ }
+ }
+}
+
+export default SelectableList
diff --git a/src/components/selectable_list/selectable_list.vue b/src/components/selectable_list/selectable_list.vue
new file mode 100644
index 00000000..ba1e5266
--- /dev/null
+++ b/src/components/selectable_list/selectable_list.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+ toggle(checked, item)" />
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index 6ee103c7..6890220f 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -42,9 +42,7 @@
-
+
@@ -330,6 +328,7 @@
textarea {
width: 100%;
+ max-width: 100%;
height: 100px;
}
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/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,
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..e1d3ff57 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -11,7 +11,7 @@
{{user.name}}
-
+
@@ -99,6 +99,8 @@
+
+
@@ -160,7 +162,7 @@
max-width: 100%;
max-height: 400px;
- .emoji {
+ &.emoji {
width: 32px;
height: 32px;
}
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 1df06fe6..4eddb8b1 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -1,47 +1,37 @@
-import { compose } from 'vue-compose'
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 List from '../list/list.vue'
import withLoadMore from '../../hocs/with_load_more/with_load_more'
-import withList from '../../hocs/with_list/with_list'
-const FollowerList = compose(
- withLoadMore({
- fetch: (props, $store) => $store.dispatch('addFollowers', props.userId),
- select: (props, $store) => get($store.getters.findUser(props.userId), 'followers', []),
- destory: (props, $store) => $store.dispatch('clearFollowers', props.userId),
- childPropName: 'entries',
- additionalPropNames: ['userId']
- }),
- withList({ getEntryProps: user => ({ user }) })
-)(FollowCard)
+const FollowerList = withLoadMore({
+ fetch: (props, $store) => $store.dispatch('fetchFollowers', props.userId),
+ select: (props, $store) => get($store.getters.findUser(props.userId), 'followerIds', []).map(id => $store.getters.findUser(id)),
+ destroy: (props, $store) => $store.dispatch('clearFollowers', props.userId),
+ childPropName: 'items',
+ additionalPropNames: ['userId']
+})(List)
-const FriendList = compose(
- withLoadMore({
- fetch: (props, $store) => $store.dispatch('addFriends', props.userId),
- select: (props, $store) => get($store.getters.findUser(props.userId), 'friends', []),
- destory: (props, $store) => $store.dispatch('clearFriends', props.userId),
- childPropName: 'entries',
- additionalPropNames: ['userId']
- }),
- withList({ getEntryProps: user => ({ user }) })
-)(FollowCard)
+const FriendList = withLoadMore({
+ fetch: (props, $store) => $store.dispatch('fetchFriends', props.userId),
+ select: (props, $store) => get($store.getters.findUser(props.userId), 'friendIds', []).map(id => $store.getters.findUser(id)),
+ destroy: (props, $store) => $store.dispatch('clearFriends', props.userId),
+ childPropName: 'items',
+ additionalPropNames: ['userId']
+})(List)
const UserProfile = {
data () {
return {
error: false,
- fetchedUserId: null
+ userId: null
}
},
created () {
- if (!this.user.id) {
- this.fetchUserId()
- .then(() => this.startUp())
- } else {
- this.startUp()
- }
+ const routeParams = this.$route.params
+ this.load(routeParams.name || routeParams.id)
},
destroyed () {
this.cleanUp()
@@ -56,26 +46,12 @@ const UserProfile = {
media () {
return this.$store.state.statuses.timelines.media
},
- userId () {
- return this.$route.params.id || this.user.id || this.fetchedUserId
- },
- userName () {
- return this.$route.params.name || this.user.screen_name
- },
isUs () {
return this.userId && this.$store.state.users.currentUser.id &&
this.userId === this.$store.state.users.currentUser.id
},
- userInStore () {
- const routeParams = this.$route.params
- // This needs fetchedUserId so that computed will be refreshed when user is fetched
- return this.$store.getters.findUser(this.fetchedUserId || routeParams.name || routeParams.id)
- },
user () {
- if (this.userInStore) {
- return this.userInStore
- }
- return {}
+ return this.$store.getters.findUser(this.userId)
},
isExternal () {
return this.$route.name === 'external-user-profile'
@@ -88,39 +64,36 @@ const UserProfile = {
}
},
methods: {
- startFetchFavorites () {
- if (this.isUs) {
- this.$store.dispatch('startFetching', { timeline: 'favorites', userId: this.userId })
- }
- },
- fetchUserId () {
- let fetchPromise
- if (this.userId && !this.$route.params.name) {
- fetchPromise = this.$store.dispatch('fetchUser', this.userId)
+ load (userNameOrId) {
+ // Check if user data is already loaded in store
+ const user = this.$store.getters.findUser(userNameOrId)
+ if (user) {
+ this.userId = user.id
+ this.fetchTimelines()
} else {
- fetchPromise = this.$store.dispatch('fetchUser', this.userName)
+ this.$store.dispatch('fetchUser', userNameOrId)
.then(({ id }) => {
- this.fetchedUserId = id
+ this.userId = id
+ this.fetchTimelines()
+ })
+ .catch((reason) => {
+ const errorMessage = get(reason, 'error.error')
+ if (errorMessage === 'No user with such user_id') { // Known error
+ this.error = this.$t('user_profile.profile_does_not_exist')
+ } else if (errorMessage) {
+ this.error = errorMessage
+ } else {
+ this.error = this.$t('user_profile.profile_loading_error')
+ }
})
}
- return fetchPromise
- .catch((reason) => {
- const errorMessage = get(reason, 'error.error')
- if (errorMessage === 'No user with such user_id') { // Known error
- this.error = this.$t('user_profile.profile_does_not_exist')
- } else if (errorMessage) {
- this.error = errorMessage
- } else {
- this.error = this.$t('user_profile.profile_loading_error')
- }
- })
- .then(() => this.startUp())
},
- startUp () {
- if (this.userId) {
- this.$store.dispatch('startFetching', { timeline: 'user', userId: this.userId })
- this.$store.dispatch('startFetching', { timeline: 'media', userId: this.userId })
- this.startFetchFavorites()
+ fetchTimelines () {
+ const userId = this.userId
+ this.$store.dispatch('startFetchingTimeline', { timeline: 'user', userId })
+ this.$store.dispatch('startFetchingTimeline', { timeline: 'media', userId })
+ if (this.isUs) {
+ this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId })
}
},
cleanUp () {
@@ -133,18 +106,16 @@ const UserProfile = {
}
},
watch: {
- // userId can be undefined if we don't know it yet
- userId (newVal) {
+ '$route.params.id': function (newVal) {
if (newVal) {
this.cleanUp()
- this.startUp()
+ this.load(newVal)
}
},
- userName () {
- if (this.$route.params.name) {
- this.fetchUserId()
+ '$route.params.name': function (newVal) {
+ if (newVal) {
this.cleanUp()
- this.startUp()
+ this.load(newVal)
}
},
$route () {
@@ -155,7 +126,9 @@ const UserProfile = {
UserCard,
Timeline,
FollowerList,
- FriendList
+ FriendList,
+ ModerationTools,
+ FollowCard
}
}
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index d449eb85..71c625b7 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -1,6 +1,6 @@
-
+
-
+
+
+
+
+
-
+
+
+
+
+
this.$store.getters.findUser(userId))
+ }
+ },
mounted () {
this.search(this.query)
},
@@ -33,10 +39,10 @@ const userSearch = {
return
}
this.loading = true
- userSearchApi.search({query, store: this.$store})
+ this.$store.dispatch('searchUsers', query)
.then((res) => {
this.loading = false
- this.users = res
+ this.userIds = map(res, 'id')
})
}
}
diff --git a/src/components/user_search/user_search.vue b/src/components/user_search/user_search.vue
index 1269eea6..890b3c13 100644
--- a/src/components/user_search/user_search.vue
+++ b/src/components/user_search/user_search.vue
@@ -13,7 +13,7 @@
-
+
diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js
index b6a0479d..e88ee612 100644
--- a/src/components/user_settings/user_settings.js
+++ b/src/components/user_settings/user_settings.js
@@ -1,6 +1,7 @@
-import { compose } from 'vue-compose'
import unescape from 'lodash/unescape'
import get from 'lodash/get'
+import map from 'lodash/map'
+import reject from 'lodash/reject'
import TabSwitcher from '../tab_switcher/tab_switcher.js'
import ImageCropper from '../image_cropper/image_cropper.vue'
import StyleSwitcher from '../style_switcher/style_switcher.vue'
@@ -8,27 +9,24 @@ import ScopeSelector from '../scope_selector/scope_selector.vue'
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
import BlockCard from '../block_card/block_card.vue'
import MuteCard from '../mute_card/mute_card.vue'
+import SelectableList from '../selectable_list/selectable_list.vue'
+import ProgressButton from '../progress_button/progress_button.vue'
import EmojiInput from '../emoji-input/emoji-input.vue'
+import Autosuggest from '../autosuggest/autosuggest.vue'
import withSubscription from '../../hocs/with_subscription/with_subscription'
-import withList from '../../hocs/with_list/with_list'
+import userSearchApi from '../../services/new_api/user_search.js'
-const BlockList = compose(
- withSubscription({
- fetch: (props, $store) => $store.dispatch('fetchBlocks'),
- select: (props, $store) => get($store.state.users.currentUser, 'blockIds', []),
- childPropName: 'entries'
- }),
- withList({ getEntryProps: userId => ({ userId }) })
-)(BlockCard)
+const BlockList = withSubscription({
+ fetch: (props, $store) => $store.dispatch('fetchBlocks'),
+ select: (props, $store) => get($store.state.users.currentUser, 'blockIds', []),
+ childPropName: 'items'
+})(SelectableList)
-const MuteList = compose(
- withSubscription({
- fetch: (props, $store) => $store.dispatch('fetchMutes'),
- select: (props, $store) => get($store.state.users.currentUser, 'muteIds', []),
- childPropName: 'entries'
- }),
- withList({ getEntryProps: userId => ({ userId }) })
-)(MuteCard)
+const MuteList = withSubscription({
+ fetch: (props, $store) => $store.dispatch('fetchMutes'),
+ select: (props, $store) => get($store.state.users.currentUser, 'muteIds', []),
+ childPropName: 'items'
+})(SelectableList)
const UserSettings = {
data () {
@@ -73,7 +71,11 @@ const UserSettings = {
ImageCropper,
BlockList,
MuteList,
- EmojiInput
+ EmojiInput,
+ Autosuggest,
+ BlockCard,
+ MuteCard,
+ ProgressButton
},
computed: {
user () {
@@ -334,6 +336,40 @@ const UserSettings = {
if (window.confirm(`${this.$i18n.t('settings.revoke_token')}?`)) {
this.$store.dispatch('revokeToken', id)
}
+ },
+ filterUnblockedUsers (userIds) {
+ return reject(userIds, (userId) => {
+ const user = this.$store.getters.findUser(userId)
+ return !user || user.statusnet_blocking || user.id === this.$store.state.users.currentUser.id
+ })
+ },
+ filterUnMutedUsers (userIds) {
+ return reject(userIds, (userId) => {
+ const user = this.$store.getters.findUser(userId)
+ return !user || user.muted || user.id === this.$store.state.users.currentUser.id
+ })
+ },
+ queryUserIds (query) {
+ return userSearchApi.search({query, store: this.$store})
+ .then((users) => {
+ this.$store.dispatch('addNewUsers', users)
+ return map(users, 'id')
+ })
+ },
+ blockUsers (ids) {
+ return this.$store.dispatch('blockUsers', ids)
+ },
+ unblockUsers (ids) {
+ return this.$store.dispatch('unblockUsers', ids)
+ },
+ muteUsers (ids) {
+ return this.$store.dispatch('muteUsers', ids)
+ },
+ unmuteUsers (ids) {
+ return this.$store.dispatch('unmuteUsers', ids)
+ },
+ identity (value) {
+ return value
}
}
}
diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue
index c08698dc..d68e68fa 100644
--- a/src/components/user_settings/user_settings.vue
+++ b/src/components/user_settings/user_settings.vue
@@ -22,7 +22,7 @@
{{$t('settings.name_bio')}}
{{$t('settings.name')}}
-
-
+
+
+
+
+
+ {{ $t('user_card.block') }}
+ {{ $t('user_card.block_progress') }}
+
+
+ {{ $t('user_card.unblock') }}
+ {{ $t('user_card.unblock_progress') }}
+
+
+
+
{{$t('settings.no_blocks')}}
-
+
-
+
+
+
+
+
+ {{ $t('user_card.mute') }}
+ {{ $t('user_card.mute_progress') }}
+
+
+ {{ $t('user_card.unmute') }}
+ {{ $t('user_card.unmute_progress') }}
+
+
+
+
{{$t('settings.no_mutes')}}
-
+
@@ -262,5 +298,19 @@
text-align: right;
}
}
+
+ &-usersearch-wrapper {
+ padding: 1em;
+ }
+
+ &-bulk-actions {
+ text-align: right;
+ padding: 0 1em;
+ min-height: 28px;
+
+ button {
+ width: 10em;
+ }
+ }
}
diff --git a/src/components/who_to_follow/who_to_follow.vue b/src/components/who_to_follow/who_to_follow.vue
index 1630f5ac..8bc9a728 100644
--- a/src/components/who_to_follow/who_to_follow.vue
+++ b/src/components/who_to_follow/who_to_follow.vue
@@ -4,7 +4,7 @@
{{$t('who_to_follow.who_to_follow')}}
-
+
diff --git a/src/hocs/with_list/with_list.js b/src/hocs/with_list/with_list.js
deleted file mode 100644
index 896f8fc8..00000000
--- a/src/hocs/with_list/with_list.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import Vue from 'vue'
-import map from 'lodash/map'
-import isEmpty from 'lodash/isEmpty'
-import './with_list.scss'
-
-const defaultEntryPropsGetter = entry => ({ entry })
-const defaultKeyGetter = entry => entry.id
-
-const withList = ({
- getEntryProps = defaultEntryPropsGetter, // function to accept entry and index values and return props to be passed into the item component
- getKey = defaultKeyGetter // funciton to accept entry and index values and return key prop value
-}) => (ItemComponent) => (
- Vue.component('withList', {
- props: [
- 'entries', // array of entry
- 'entryProps', // additional props to be passed into each entry
- 'entryListeners' // additional event listeners to be passed into each entry
- ],
- render (createElement) {
- return (
-
- {map(this.entries, (entry, index) => {
- const props = {
- key: getKey(entry, index),
- props: {
- ...this.$props.entryProps,
- ...getEntryProps(entry, index)
- },
- on: this.$props.entryListeners
- }
- return
- })}
- {isEmpty(this.entries) && this.$slots.empty &&
{this.$slots.empty}
}
-
- )
- }
- })
-)
-
-export default withList
diff --git a/src/hocs/with_list/with_list.scss b/src/hocs/with_list/with_list.scss
deleted file mode 100644
index c6e13d5b..00000000
--- a/src/hocs/with_list/with_list.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-.with-list {
- &-empty-content {
- text-align: center;
- padding: 10px;
- }
-}
\ No newline at end of file
diff --git a/src/hocs/with_load_more/with_load_more.scss b/src/hocs/with_load_more/with_load_more.scss
index 1a0a9c40..4cefe2be 100644
--- a/src/hocs/with_load_more/with_load_more.scss
+++ b/src/hocs/with_load_more/with_load_more.scss
@@ -1,10 +1,16 @@
+
+@import '../../_variables.scss';
+
.with-load-more {
&-footer {
padding: 10px;
text-align: center;
+ border-top: 1px solid;
+ border-top-color: $fallback--border;
+ border-top-color: var(--border, $fallback--border);
.error {
font-size: 14px;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/i18n/cs.json b/src/i18n/cs.json
index 020092a6..5f2f2b71 100644
--- a/src/i18n/cs.json
+++ b/src/i18n/cs.json
@@ -73,7 +73,8 @@
"content_type": {
"text/plain": "Prostý text",
"text/html": "HTML",
- "text/markdown": "Markdown"
+ "text/markdown": "Markdown",
+ "text/bbcode": "BBCode"
},
"content_warning": "Předmět (volitelný)",
"default": "Právě jsem přistál v L.A.",
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 1e82cd0a..711e8d31 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",
@@ -76,7 +77,8 @@
"content_type": {
"text/plain": "Plain text",
"text/html": "HTML",
- "text/markdown": "Markdown"
+ "text/markdown": "Markdown",
+ "text/bbcode": "BBCode"
},
"content_warning": "Subject (optional)",
"default": "Just landed in L.A.",
@@ -111,6 +113,9 @@
"password_confirmation_match": "should be the same as password"
}
},
+ "selectable_list": {
+ "select_all": "Select all"
+ },
"settings": {
"app_name": "App name",
"attachmentRadius": "Attachments",
@@ -216,6 +221,8 @@
"reply_visibility_self": "Only show replies directed at me",
"saving_err": "Error saving settings",
"saving_ok": "Settings saved",
+ "search_user_to_block": "Search whom you want to block",
+ "search_user_to_mute": "Search whom you want to mute",
"security_tab": "Security",
"scope_copy": "Copy scope when replying (DMs are always copied)",
"minimal_scopes_mode": "Minimize post scope selection options",
@@ -403,7 +410,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/oc.json b/src/i18n/oc.json
index 9214799d..a5826239 100644
--- a/src/i18n/oc.json
+++ b/src/i18n/oc.json
@@ -20,7 +20,10 @@
"submit": "Mandar",
"more": "Mai",
"generic_error": "Una error s’es producha",
- "optional": "opcional"
+ "optional": "opcional",
+ "show_more": "Mostrar mai",
+ "show_less": "Mostrar mens",
+ "cancel": "Anullar"
},
"image_cropper": {
"crop_picture": "Talhar l’imatge",
@@ -74,11 +77,13 @@
"content_type": {
"text/plain": "Tèxte brut",
"text/html": "HTML",
- "text/markdown": "Markdown"
+ "text/markdown": "Markdown",
+ "text/bbcode": "BBCode"
},
"content_warning": "Avís de contengut (opcional)",
"default": "Escrivètz aquí vòstre estatut.",
- "direct_warning": "Aquesta publicacion serà pas que visibla pels utilizaires mencionats.",
+ "direct_warning_to_all": "Aquesta publicacion serà pas que visibla pels utilizaires mencionats.",
+ "direct_warning_to_first_only": "Aquesta publicacion serà pas que visibla pels utilizaires mencionats a la debuta del messatge.",
"posting": "Mandadís",
"scope": {
"direct": "Dirècte - Publicar pels utilizaires mencionats solament",
@@ -108,6 +113,9 @@
"password_confirmation_match": "deu èsser lo meteis senhal"
}
},
+ "selectable_list": {
+ "select_all": "O seleccionar tot"
+ },
"settings": {
"app_name": "Nom de l’aplicacion",
"attachmentRadius": "Pèças juntas",
@@ -213,8 +221,11 @@
"reply_visibility_self": "Mostrar pas que las responsas que me son destinadas",
"saving_err": "Error en enregistrant los paramètres",
"saving_ok": "Paramètres enregistrats",
- "scope_copy": "Copiar lo nivèl de confidencialitat per las responsas (Totjorn aissí pels Messatges Dirèctes)",
+ "search_user_to_block": "Cercatz qual volètz blocar",
+ "search_user_to_mute": "Cercatz qual volètz rescondre",
"security_tab": "Seguretat",
+ "scope_copy": "Copiar lo nivèl de confidencialitat per las responsas (Totjorn aissí pels Messatges Dirèctes)",
+ "minimal_scopes_mode": "Minimizar lo nombre d’opcions per publicacion",
"set_new_avatar": "Definir un nòu avatar",
"set_new_profile_background": "Definir un nòu fons de perfil",
"set_new_profile_banner": "Definir una nòva bandièra de perfil",
@@ -349,6 +360,11 @@
"checkbox": "Ai legit los tèrmes e condicions d’utilizacion",
"link": "un pichon ligam simpatic"
}
+ },
+ "version": {
+ "title": "Version",
+ "backend_version": "Version Backend",
+ "frontend_version": "Version Frontend"
}
},
"timeline": {
@@ -394,7 +410,26 @@
"block_progress": "Blocatge...",
"unmute": "Tornar mostrar",
"unmute_progress": "Afichatge...",
- "mute_progress": "A amagar..."
+ "mute_progress": "A amagar...",
+ "admin_menu": {
+ "moderation": "Moderacion",
+ "grant_admin": "Passar Admin",
+ "revoke_admin": "Revocar Admin",
+ "grant_moderator": "Passar Moderator",
+ "revoke_moderator": "Revocar Moderator",
+ "activate_account": "Activar lo compte",
+ "deactivate_account": "Desactivar lo compte",
+ "delete_account": "Suprimir lo compte",
+ "force_nsfw": "Marcar totas las publicacions coma sensiblas",
+ "strip_media": "Tirar los mèdias de las publicacions",
+ "force_unlisted": "Forçar las publicacions en pas-listadas",
+ "sandbox": "Forçar las publicacions en seguidors solament",
+ "disable_remote_subscription": "Desactivar lo seguiment d’utilizaire d’instàncias alonhadas",
+ "disable_any_subscription": "Desactivar tot seguiment",
+ "quarantine": "Defendre la federacion de las publicacions de l’utilizaire",
+ "delete_user": "Suprimir l’utilizaire",
+ "delete_user_confirmation": "Volètz vertadièrament far aquò ? Aquesta accion se pòt pas anullar."
+ }
},
"user_profile": {
"timeline_title": "Flux utilizaire",
@@ -426,4 +461,4 @@
"TiB": "Tio"
}
}
-}
\ No newline at end of file
+}
diff --git a/src/i18n/pl.json b/src/i18n/pl.json
index 8efce168..715e5d6e 100644
--- a/src/i18n/pl.json
+++ b/src/i18n/pl.json
@@ -74,7 +74,8 @@
"content_type": {
"text/plain": "Czysty tekst",
"text/html": "HTML",
- "text/markdown": "Markdown"
+ "text/markdown": "Markdown",
+ "text/bbcode": "BBCode"
},
"content_warning": "Temat (nieobowiązkowy)",
"default": "Właśnie wróciłem z kościoła",
@@ -431,4 +432,4 @@
"TiB": "TiB"
}
}
-}
\ No newline at end of file
+}
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/main.js b/src/main.js
index 9ffc3727..725f5806 100644
--- a/src/main.js
+++ b/src/main.js
@@ -22,6 +22,7 @@ import pushNotifications from './lib/push_notifications_plugin.js'
import messages from './i18n/messages.js'
import VueChatScroll from 'vue-chat-scroll'
+import VueClickOutside from 'v-click-outside'
import afterStoreSetup from './boot/after_store.js'
@@ -39,6 +40,7 @@ Vue.use(VueTimeago, {
})
Vue.use(VueI18n)
Vue.use(VueChatScroll)
+Vue.use(VueClickOutside)
const i18n = new VueI18n({
// By default, use the browser locale, we will update it if neccessary
@@ -59,6 +61,11 @@ const persistedStateOptions = {
const persistedState = await createPersistedState(persistedStateOptions)
const store = new Vuex.Store({
modules: {
+ i18n: {
+ getters: {
+ i18n: () => i18n
+ }
+ },
interface: interfaceModule,
instance: instanceModule,
statuses: statusesModule,
diff --git a/src/modules/api.js b/src/modules/api.js
index 31cb55c6..7ed3edac 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/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)
}
}
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index 8e0203e3..e70c2400 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
+})
+
export const defaultState = () => ({
allStatuses: [],
allStatusesObject: {},
+ conversationsObject: {},
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: {
@@ -111,6 +113,39 @@ const sortTimeline = (timeline) => {
return timeline
}
+// Add status to the global storages (arrays and objects maintaining statuses) except timelines
+const addStatusToGlobalStorage = (state, data) => {
+ const result = mergeOrAdd(state.allStatuses, state.allStatusesObject, data)
+ if (result.new) {
+ // Add to conversation
+ const status = result.item
+ const conversationsObject = state.conversationsObject
+ const conversationId = status.statusnet_conversation_id
+ if (conversationsObject[conversationId]) {
+ conversationsObject[conversationId].push(status)
+ } else {
+ set(conversationsObject, conversationId, [status])
+ }
+ }
+ return result
+}
+
+// Remove status from the global storages (arrays and objects maintaining statuses) except timelines
+const removeStatusFromGlobalStorage = (state, status) => {
+ remove(state.allStatuses, { id: status.id })
+
+ // TODO: Need to remove from allStatusesObject?
+
+ // Remove possible notification
+ remove(state.notifications.data, ({action: {id}}) => id === status.id)
+
+ // Remove from conversation
+ const conversationId = status.statusnet_conversation_id
+ if (state.conversationsObject[conversationId]) {
+ remove(state.conversationsObject[conversationId], { id: status.id })
+ }
+}
+
const addNewStatuses = (state, { statuses, showImmediately = false, timeline, user = {}, noIdUpdate = false, userId }) => {
// Sanity check
if (!isArray(statuses)) {
@@ -118,7 +153,6 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
}
const allStatuses = state.allStatuses
- const allStatusesObject = state.allStatusesObject
const timelineObject = state.timelines[timeline]
const maxNew = statuses.length > 0 ? maxBy(statuses, 'id').id : 0
@@ -141,7 +175,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
}
const addStatus = (data, showImmediately, addToTimeline = true) => {
- const result = mergeOrAdd(allStatuses, allStatusesObject, data)
+ const result = addStatusToGlobalStorage(state, data)
const status = result.item
if (result.new) {
@@ -235,16 +269,13 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
},
'deletion': (deletion) => {
const uri = deletion.uri
-
- // Remove possible notification
const status = find(allStatuses, {uri})
if (!status) {
return
}
- remove(state.notifications.data, ({action: {id}}) => id === status.id)
+ removeStatusFromGlobalStorage(state, status)
- remove(allStatuses, { uri })
if (timeline) {
remove(timelineObject.statuses, { uri })
remove(timelineObject.visibleStatuses, { uri })
@@ -271,12 +302,12 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
}
}
-const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes }) => {
- const allStatuses = state.allStatuses
- const allStatusesObject = state.allStatusesObject
+const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => {
each(notifications, (notification) => {
- notification.action = mergeOrAdd(allStatuses, allStatusesObject, notification.action).item
- notification.status = notification.status && mergeOrAdd(allStatuses, allStatusesObject, notification.status).item
+ if (notification.type !== 'follow') {
+ notification.action = addStatusToGlobalStorage(state, notification.action).item
+ notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
+ }
// Only add a new notification if we don't have one for the same action
if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
@@ -292,15 +323,32 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
if ('Notification' in window && window.Notification.permission === 'granted') {
const notifObj = {}
- const action = notification.action
- const title = action.user.name
- notifObj.icon = action.user.profile_image_url
- notifObj.body = action.text // there's a problem that it doesn't put a space before links tho
+ const status = notification.status
+ const title = notification.from_profile.name
+ notifObj.icon = notification.from_profile.profile_image_url
+ let i18nString
+ switch (notification.type) {
+ case 'like':
+ i18nString = 'favorited_you'
+ break
+ case 'repeat':
+ i18nString = 'repeated_you'
+ break
+ case 'follow':
+ i18nString = 'followed_you'
+ break
+ }
+
+ if (i18nString) {
+ notifObj.body = rootGetters.i18n.t('notifications.' + i18nString)
+ } else {
+ notifObj.body = notification.status.text
+ }
// Shows first attached non-nsfw image, if any. Should add configuration for this somehow...
- if (action.attachments && action.attachments.length > 0 && !action.nsfw &&
- action.attachments[0].mimetype.startsWith('image/')) {
- notifObj.image = action.attachments[0].url
+ if (status && status.attachments && status.attachments.length > 0 && !status.nsfw &&
+ status.attachments[0].mimetype.startsWith('image/')) {
+ notifObj.image = status.attachments[0].url
}
if (!notification.seen && !state.notifications.desktopNotificationSilence && visibleNotificationTypes.includes(notification.type)) {
@@ -340,9 +388,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]) => {
@@ -352,6 +397,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
@@ -378,6 +426,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
},
@@ -413,8 +468,8 @@ const statuses = {
addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId }) {
commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId })
},
- addNewNotifications ({ rootState, commit, dispatch }, { notifications, older }) {
- commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older })
+ addNewNotifications ({ rootState, commit, dispatch, rootGetters }, { notifications, older }) {
+ commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older, rootGetters })
},
setError ({ rootState, commit }, { value }) {
commit('setError', { value })
@@ -428,16 +483,13 @@ 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 })
},
+ 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..adcab233 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -1,5 +1,6 @@
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
-import { compact, map, each, merge, find, last } from 'lodash'
+import userSearchApi from '../services/new_api/user_search.js'
+import { compact, map, each, merge, last, concat, uniq } from 'lodash'
import { set } from 'vue'
import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
import oauthApi from '../services/new_api/oauth'
@@ -32,11 +33,62 @@ const getNotificationPermission = () => {
return Promise.resolve(Notification.permission)
}
+const blockUser = (store, id) => {
+ return store.rootState.api.backendInteractor.blockUser(id)
+ .then((relationship) => {
+ store.commit('updateUserRelationship', [relationship])
+ store.commit('addBlockId', id)
+ store.commit('removeStatus', { timeline: 'friends', userId: id })
+ store.commit('removeStatus', { timeline: 'public', userId: id })
+ store.commit('removeStatus', { timeline: 'publicAndExternal', userId: id })
+ })
+}
+
+const unblockUser = (store, id) => {
+ return store.rootState.api.backendInteractor.unblockUser(id)
+ .then((relationship) => store.commit('updateUserRelationship', [relationship]))
+}
+
+const muteUser = (store, id) => {
+ return store.rootState.api.backendInteractor.muteUser(id)
+ .then((relationship) => {
+ store.commit('updateUserRelationship', [relationship])
+ store.commit('addMuteId', id)
+ })
+}
+
+const unmuteUser = (store, id) => {
+ return store.rootState.api.backendInteractor.unmuteUser(id)
+ .then((relationship) => store.commit('updateUserRelationship', [relationship]))
+}
+
export const mutations = {
setMuted (state, { user: { id }, muted }) {
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)
@@ -51,42 +103,27 @@ export const mutations = {
endLogin (state) {
state.loggingIn = false
},
- // TODO Clean after ourselves?
- addFriends (state, { id, friends }) {
+ saveFriendIds (state, { id, friendIds }) {
const user = state.usersObject[id]
- each(friends, friend => {
- if (!find(user.friends, { id: friend.id })) {
- user.friends.push(friend)
- }
- })
- user.lastFriendId = last(friends).id
+ user.friendIds = uniq(concat(user.friendIds, friendIds))
},
- addFollowers (state, { id, followers }) {
+ saveFollowerIds (state, { id, followerIds }) {
const user = state.usersObject[id]
- each(followers, follower => {
- if (!find(user.followers, { id: follower.id })) {
- user.followers.push(follower)
- }
- })
- user.lastFollowerId = last(followers).id
+ user.followerIds = uniq(concat(user.followerIds, followerIds))
},
// Because frontend doesn't have a reason to keep these stuff in memory
// outside of viewing someones user profile.
clearFriends (state, userId) {
const user = state.usersObject[userId]
- if (!user) {
- return
+ if (user) {
+ set(user, 'friendIds', [])
}
- user.friends = []
- user.lastFriendId = null
},
clearFollowers (state, userId) {
const user = state.usersObject[userId]
- if (!user) {
- return
+ if (user) {
+ set(user, 'followerIds', [])
}
- user.followers = []
- user.lastFollowerId = null
},
addNewUsers (state, users) {
each(users, (user) => mergeOrAdd(state.users, state.usersObject, user))
@@ -110,6 +147,11 @@ export const mutations = {
saveBlockIds (state, blockIds) {
state.currentUser.blockIds = blockIds
},
+ addBlockId (state, blockId) {
+ if (state.currentUser.blockIds.indexOf(blockId) === -1) {
+ state.currentUser.blockIds.push(blockId)
+ }
+ },
updateMutes (state, mutedUsers) {
// Reset muted of all fetched users
each(state.users, (user) => { user.muted = false })
@@ -118,12 +160,19 @@ export const mutations = {
saveMuteIds (state, muteIds) {
state.currentUser.muteIds = muteIds
},
+ addMuteId (state, muteId) {
+ if (state.currentUser.muteIds.indexOf(muteId) === -1) {
+ state.currentUser.muteIds.push(muteId)
+ }
+ },
setUserForStatus (state, status) {
status.user = state.usersObject[status.user.id]
},
setUserForNotification (state, notification) {
- notification.action.user = state.usersObject[notification.action.user.id]
- notification.from_profile = state.usersObject[notification.action.user.id]
+ if (notification.type !== 'follow') {
+ notification.action.user = state.usersObject[notification.action.user.id]
+ }
+ notification.from_profile = state.usersObject[notification.from_profile.id]
},
setColor (state, { user: { id }, highlighted }) {
const user = state.usersObject[id]
@@ -176,8 +225,10 @@ const users = {
})
},
fetchUserRelationship (store, id) {
- return store.rootState.api.backendInteractor.fetchUserRelationship({ id })
- .then((relationships) => store.commit('updateUserRelationship', relationships))
+ if (store.state.currentUser) {
+ store.rootState.api.backendInteractor.fetchUserRelationship({ id })
+ .then((relationships) => store.commit('updateUserRelationship', relationships))
+ }
},
fetchBlocks (store) {
return store.rootState.api.backendInteractor.fetchBlocks()
@@ -187,18 +238,17 @@ const users = {
return blocks
})
},
- blockUser (store, userId) {
- return store.rootState.api.backendInteractor.blockUser(userId)
- .then((relationship) => {
- store.commit('updateUserRelationship', [relationship])
- store.commit('removeStatus', { timeline: 'friends', userId })
- store.commit('removeStatus', { timeline: 'public', userId })
- store.commit('removeStatus', { timeline: 'publicAndExternal', userId })
- })
+ blockUser (store, id) {
+ return blockUser(store, id)
},
unblockUser (store, id) {
- return store.rootState.api.backendInteractor.unblockUser(id)
- .then((relationship) => store.commit('updateUserRelationship', [relationship]))
+ return unblockUser(store, id)
+ },
+ blockUsers (store, ids = []) {
+ return Promise.all(ids.map(id => blockUser(store, id)))
+ },
+ unblockUsers (store, ids = []) {
+ return Promise.all(ids.map(id => unblockUser(store, id)))
},
fetchMutes (store) {
return store.rootState.api.backendInteractor.fetchMutes()
@@ -209,32 +259,34 @@ const users = {
})
},
muteUser (store, id) {
- return store.rootState.api.backendInteractor.muteUser(id)
- .then((relationship) => store.commit('updateUserRelationship', [relationship]))
+ return muteUser(store, id)
},
unmuteUser (store, id) {
- return store.rootState.api.backendInteractor.unmuteUser(id)
- .then((relationship) => store.commit('updateUserRelationship', [relationship]))
+ return unmuteUser(store, id)
},
- addFriends ({ rootState, commit }, fetchBy) {
- return new Promise((resolve, reject) => {
- const user = rootState.users.usersObject[fetchBy]
- const maxId = user.lastFriendId
- rootState.api.backendInteractor.fetchFriends({ id: user.id, maxId })
- .then((friends) => {
- commit('addFriends', { id: user.id, friends })
- resolve(friends)
- }).catch(() => {
- reject()
- })
- })
+ muteUsers (store, ids = []) {
+ return Promise.all(ids.map(id => muteUser(store, id)))
},
- addFollowers ({ rootState, commit }, fetchBy) {
- const user = rootState.users.usersObject[fetchBy]
- const maxId = user.lastFollowerId
- return rootState.api.backendInteractor.fetchFollowers({ id: user.id, maxId })
+ unmuteUsers (store, ids = []) {
+ return Promise.all(ids.map(id => unmuteUser(store, id)))
+ },
+ fetchFriends ({ rootState, commit }, id) {
+ const user = rootState.users.usersObject[id]
+ const maxId = last(user.friendIds)
+ return rootState.api.backendInteractor.fetchFriends({ id, maxId })
+ .then((friends) => {
+ commit('addNewUsers', friends)
+ commit('saveFriendIds', { id, friendIds: map(friends, 'id') })
+ return friends
+ })
+ },
+ fetchFollowers ({ rootState, commit }, id) {
+ const user = rootState.users.usersObject[id]
+ const maxId = last(user.followerIds)
+ return rootState.api.backendInteractor.fetchFollowers({ id, maxId })
.then((followers) => {
- commit('addFollowers', { id: user.id, followers })
+ commit('addNewUsers', followers)
+ commit('saveFollowerIds', { id, followerIds: map(followers, 'id') })
return followers
})
},
@@ -257,6 +309,9 @@ const users = {
unregisterPushNotifications(token)
},
+ addNewUsers ({ commit }, users) {
+ commit('addNewUsers', users)
+ },
addNewStatuses (store, { statuses }) {
const users = map(statuses, 'user')
const retweetedUsers = compact(map(statuses, 'retweeted_status.user'))
@@ -287,6 +342,14 @@ const users = {
store.commit('setUserForNotification', notification)
})
},
+ searchUsers (store, query) {
+ // TODO: Move userSearch api into api.service
+ return userSearchApi.search({query, store: { state: store.rootState }})
+ .then((users) => {
+ store.commit('addNewUsers', users)
+ return users
+ })
+ },
async signUp (store, userInfo) {
store.commit('signUpPending')
@@ -331,7 +394,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) {
@@ -363,7 +427,10 @@ const users = {
}
// Start getting fresh posts.
- store.dispatch('startFetching', { timeline: 'friends' })
+ store.dispatch('startFetchingTimeline', { timeline: 'friends' })
+
+ // Start fetching notifications
+ store.dispatch('startFetchingNotifications')
// Get user mutes
store.dispatch('fetchMutes')
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 030c2f5e..6b255e9f 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -8,7 +8,6 @@ const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
const BANNER_UPDATE_URL = '/api/account/update_profile_banner.json'
const PROFILE_UPDATE_URL = '/api/account/update_profile.json'
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
-const QVITTER_USER_NOTIFICATIONS_URL = '/api/qvitter/statuses/notifications.json'
const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json'
const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
@@ -16,9 +15,14 @@ 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'
+const MASTODON_USER_NOTIFICATIONS_URL = '/api/v1/notifications'
const MASTODON_FAVORITE_URL = id => `/api/v1/statuses/${id}/favourite`
const MASTODON_UNFAVORITE_URL = id => `/api/v1/statuses/${id}/unfavourite`
const MASTODON_RETWEET_URL = id => `/api/v1/statuses/${id}/reblog`
@@ -46,7 +50,7 @@ const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute`
const MASTODON_POST_STATUS_URL = '/api/v1/statuses'
const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media'
-import { each, map } from 'lodash'
+import { each, map, concat, last } from 'lodash'
import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
import 'whatwg-fetch'
import { StatusCodeError } from '../errors/errors'
@@ -290,10 +294,23 @@ const fetchFriends = ({id, maxId, sinceId, limit = 20, credentials}) => {
}
const exportFriends = ({id, credentials}) => {
- let url = MASTODON_FOLLOWING_URL(id) + `?all=true`
- return fetch(url, { headers: authHeaders(credentials) })
- .then((data) => data.json())
- .then((data) => data.map(parseUser))
+ return new Promise(async (resolve, reject) => {
+ try {
+ let friends = []
+ let more = true
+ while (more) {
+ const maxId = friends.length > 0 ? last(friends).id : undefined
+ const users = await fetchFriends({id, maxId, credentials})
+ friends = concat(friends, users)
+ if (users.length === 0) {
+ more = false
+ }
+ }
+ resolve(friends)
+ } catch (err) {
+ reject(err)
+ }
+ })
}
const fetchFollowers = ({id, maxId, sinceId, limit = 20, credentials}) => {
@@ -352,13 +369,93 @@ 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,
friends: MASTODON_USER_HOME_TIMELINE_URL,
mentions: MENTIONS_URL,
dms: MASTODON_DIRECT_MESSAGES_TIMELINE_URL,
- notifications: QVITTER_USER_NOTIFICATIONS_URL,
+ notifications: MASTODON_USER_NOTIFICATIONS_URL,
'publicAndExternal': MASTODON_PUBLIC_TIMELINE,
user: MASTODON_USER_TIMELINE_URL,
media: MASTODON_USER_TIMELINE_URL,
@@ -666,6 +763,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..75bba92b 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}) => {
@@ -58,8 +59,36 @@ const backendInteractorService = (credentials) => {
return apiService.denyUser({credentials, id})
}
- const startFetching = ({timeline, store, userId = false, tag}) => {
- 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 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})
@@ -97,13 +126,20 @@ const backendInteractorService = (credentials) => {
fetchUserRelationship,
fetchAllFollowing,
verifyCredentials: apiService.verifyCredentials,
- startFetching,
+ startFetchingTimeline,
+ startFetchingNotifications,
fetchMutes,
muteUser,
unmuteUser,
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..e706e7d9 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -39,7 +39,7 @@ export const parseUser = (data) => {
return output
}
- // output.name = ??? missing
+ output.name = data.display_name
output.name_html = addEmojis(data.display_name, data.emojis)
// output.description = ??? missing
@@ -67,9 +67,14 @@ 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
+ // TODO: handle is_local
output.is_local = !output.screen_name.includes('@')
} else {
output.screen_name = data.screen_name
@@ -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
@@ -119,12 +129,19 @@ export const parseUser = (data) => {
output.locked = data.locked
output.followers_count = data.followers_count
output.statuses_count = data.statuses_count
- output.friends = []
- output.followers = []
+ output.friendIds = []
+ output.followerIds = []
if (data.pleroma) {
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
}
@@ -172,28 +189,28 @@ export const parseStatus = (data) => {
output.statusnet_html = addEmojis(data.content, data.emojis)
- // Not exactly the same but works?
- output.text = data.content
+ if (data.pleroma) {
+ const { pleroma } = data
+ output.text = pleroma.content ? data.pleroma.content['text/plain'] : data.content
+ output.summary = pleroma.spoiler_text ? data.pleroma.spoiler_text['text/plain'] : data.spoiler_text
+ output.statusnet_conversation_id = data.pleroma.conversation_id
+ output.is_local = pleroma.local
+ output.in_reply_to_screen_name = data.pleroma.in_reply_to_account_acct
+ } else {
+ output.text = data.content
+ output.summary = data.spoiler_text
+ }
output.in_reply_to_status_id = data.in_reply_to_id
output.in_reply_to_user_id = data.in_reply_to_account_id
output.replies_count = data.replies_count
- // Missing!! fix in UI?
- // output.in_reply_to_screen_name = ???
-
- // Not exactly the same but works
- output.statusnet_conversation_id = data.id
-
if (output.type === 'retweet') {
output.retweeted_status = parseStatus(data.reblog)
}
- output.summary = data.spoiler_text
output.summary_html = addEmojis(data.spoiler_text, data.emojis)
output.external_url = data.url
-
- // output.is_local = ??? missing
} else {
output.favorited = data.favorited
output.fave_num = data.fave_num
@@ -221,7 +238,6 @@ export const parseStatus = (data) => {
output.in_reply_to_status_id = data.in_reply_to_status_id
output.in_reply_to_user_id = data.in_reply_to_user_id
output.in_reply_to_screen_name = data.in_reply_to_screen_name
-
output.statusnet_conversation_id = data.statusnet_conversation_id
if (output.type === 'retweet') {
@@ -272,9 +288,11 @@ export const parseNotification = (data) => {
if (masto) {
output.type = mastoDict[data.type] || data.type
- // output.seen = ??? missing
- output.status = parseStatus(data.status)
- output.action = output.status // not sure
+ output.seen = data.pleroma.is_seen
+ output.status = output.type === 'follow'
+ ? null
+ : parseStatus(data.status)
+ output.action = output.status // TODO: Refactor, this is unneeded
output.from_profile = parseUser(data.account)
} else {
const parsedNotice = parseStatus(data.notice)
diff --git a/src/services/follow_manipulate/follow_manipulate.js b/src/services/follow_manipulate/follow_manipulate.js
index 51dafe84..b2486e7c 100644
--- a/src/services/follow_manipulate/follow_manipulate.js
+++ b/src/services/follow_manipulate/follow_manipulate.js
@@ -23,18 +23,12 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
// For locked users we just mark it that we sent the follow request
if (updated.locked) {
- resolve({
- sent: true,
- updated
- })
+ resolve({ sent: true })
}
if (updated.following) {
// If we get result immediately, just stop.
- resolve({
- sent: false,
- updated
- })
+ resolve({ sent: false })
}
// But usually we don't get result immediately, so we ask server
@@ -48,16 +42,10 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
.then((following) => {
if (following) {
// We confirmed and everything's good.
- resolve({
- sent: false,
- updated
- })
+ resolve({ sent: false })
} else {
// If after all the tries, just treat it as if user is locked
- resolve({
- sent: false,
- updated
- })
+ resolve({ sent: false })
}
})
})
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index cd8f3f9e..8afd114e 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -10,8 +10,8 @@ export const visibleTypes = store => ([
].filter(_ => _))
const sortById = (a, b) => {
- const seqA = Number(a.action.id)
- const seqB = Number(b.action.id)
+ const seqA = Number(a.id)
+ const seqB = Number(b.id)
const isSeqA = !Number.isNaN(seqA)
const isSeqB = !Number.isNaN(seqB)
if (isSeqA && isSeqB) {
@@ -21,7 +21,7 @@ const sortById = (a, b) => {
} else if (!isSeqA && isSeqB) {
return -1
} else {
- return a.action.id > b.action.id ? -1 : 1
+ return a.id > b.id ? -1 : 1
}
}
diff --git a/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js
index 3ecdae6a..60c497ae 100644
--- a/src/services/notifications_fetcher/notifications_fetcher.service.js
+++ b/src/services/notifications_fetcher/notifications_fetcher.service.js
@@ -11,29 +11,35 @@ const fetchAndUpdate = ({store, credentials, older = false}) => {
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.notifications
+ args['timeline'] = 'notifications'
if (older) {
if (timelineData.minId !== Number.POSITIVE_INFINITY) {
args['until'] = timelineData.minId
}
+ return fetchNotifications({ store, args, older })
} else {
- // load unread notifications repeadedly to provide consistency between browser tabs
+ // fetch new notifications
+ if (timelineData.maxId !== Number.POSITIVE_INFINITY) {
+ args['since'] = timelineData.maxId
+ }
+ const result = fetchNotifications({ store, args, older })
+
+ // load unread notifications repeatedly to provide consistency between browser tabs
const notifications = timelineData.data
const unread = notifications.filter(n => !n.seen).map(n => n.id)
- if (!unread.length) {
- args['since'] = timelineData.maxId
- } else {
- args['since'] = Math.min(...unread) - 1
- if (timelineData.maxId !== Math.max(...unread)) {
- args['until'] = Math.max(...unread, args['since'] + 20)
- }
+ if (unread.length) {
+ args['since'] = Math.min(...unread)
+ fetchNotifications({ store, args, older })
}
+
+ return result
}
+}
- args['timeline'] = 'notifications'
-
+const fetchNotifications = ({ store, args, older }) => {
return apiService.fetchTimeline(args)
.then((notifications) => {
- update({store, notifications, older})
+ update({ store, notifications, older })
return notifications
}, () => store.dispatch('setNotificationsError', { value: true }))
.catch(() => store.dispatch('setNotificationsError', { value: true }))
diff --git a/static/font/config.json b/static/font/config.json
index 844853b3..b73f2ad4 100644
--- a/static/font/config.json
+++ b/static/font/config.json
@@ -245,6 +245,12 @@
"css": "bell-alt",
"code": 61683,
"src": "fontawesome"
+ },
+ {
+ "uid": "5bb103cd29de77e0e06a52638527b575",
+ "css": "wrench",
+ "code": 59418,
+ "src": "fontawesome"
}
]
}
\ No newline at end of file
diff --git a/static/font/css/fontello-codes.css b/static/font/css/fontello-codes.css
index 0b738b0c..b57c5620 100755
--- a/static/font/css/fontello-codes.css
+++ b/static/font/css/fontello-codes.css
@@ -24,6 +24,8 @@
.icon-adjust:before { content: '\e816'; } /* '' */
.icon-edit:before { content: '\e817'; } /* '' */
.icon-pencil:before { content: '\e818'; } /* '' */
+.icon-verified:before { content: '\e819'; } /* '' */
+.icon-wrench:before { content: '\e81a'; } /* '' */
.icon-spin3:before { content: '\e832'; } /* '' */
.icon-spin4:before { content: '\e834'; } /* '' */
.icon-link-ext:before { content: '\f08e'; } /* '' */
diff --git a/static/font/css/fontello-embedded.css b/static/font/css/fontello-embedded.css
index d6960970..c69c8b9f 100755
--- a/static/font/css/fontello-embedded.css
+++ b/static/font/css/fontello-embedded.css
@@ -1,15 +1,15 @@
@font-face {
font-family: 'fontello';
- src: url('../font/fontello.eot?89861281');
- src: url('../font/fontello.eot?89861281#iefix') format('embedded-opentype'),
- url('../font/fontello.svg?89861281#fontello') format('svg');
+ src: url('../font/fontello.eot?54523265');
+ src: url('../font/fontello.eot?54523265#iefix') format('embedded-opentype'),
+ url('../font/fontello.svg?54523265#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'fontello';
- src: url('data:application/octet-stream;base64,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') format('woff'),
- url('data:application/octet-stream;base64,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') format('truetype');
+ src: url('data:application/octet-stream;base64,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') format('woff'),
+ url('data:application/octet-stream;base64,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') format('truetype');
}
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
@@ -17,7 +17,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'fontello';
- src: url('../font/fontello.svg?89861281#fontello') format('svg');
+ src: url('../font/fontello.svg?54523265#fontello') format('svg');
}
}
*/
@@ -77,6 +77,8 @@
.icon-adjust:before { content: '\e816'; } /* '' */
.icon-edit:before { content: '\e817'; } /* '' */
.icon-pencil:before { content: '\e818'; } /* '' */
+.icon-verified:before { content: '\e819'; } /* '' */
+.icon-wrench:before { content: '\e81a'; } /* '' */
.icon-spin3:before { content: '\e832'; } /* '' */
.icon-spin4:before { content: '\e834'; } /* '' */
.icon-link-ext:before { content: '\f08e'; } /* '' */
diff --git a/static/font/css/fontello-ie7-codes.css b/static/font/css/fontello-ie7-codes.css
index 50273d32..981463a8 100755
--- a/static/font/css/fontello-ie7-codes.css
+++ b/static/font/css/fontello-ie7-codes.css
@@ -24,6 +24,8 @@
.icon-adjust { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-edit { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-pencil { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
+.icon-verified { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
+.icon-wrench { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-spin3 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-spin4 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
diff --git a/static/font/css/fontello-ie7.css b/static/font/css/fontello-ie7.css
index adc56c4b..c2e8bc24 100755
--- a/static/font/css/fontello-ie7.css
+++ b/static/font/css/fontello-ie7.css
@@ -35,6 +35,8 @@
.icon-adjust { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-edit { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-pencil { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
+.icon-verified { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
+.icon-wrench { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-spin3 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-spin4 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
diff --git a/static/font/css/fontello.css b/static/font/css/fontello.css
index 1cd1fd45..fc23c41a 100755
--- a/static/font/css/fontello.css
+++ b/static/font/css/fontello.css
@@ -1,11 +1,11 @@
@font-face {
font-family: 'fontello';
- src: url('../font/fontello.eot?72648396');
- src: url('../font/fontello.eot?72648396#iefix') format('embedded-opentype'),
- url('../font/fontello.woff2?72648396') format('woff2'),
- url('../font/fontello.woff?72648396') format('woff'),
- url('../font/fontello.ttf?72648396') format('truetype'),
- url('../font/fontello.svg?72648396#fontello') format('svg');
+ src: url('../font/fontello.eot?11878820');
+ src: url('../font/fontello.eot?11878820#iefix') format('embedded-opentype'),
+ url('../font/fontello.woff2?11878820') format('woff2'),
+ url('../font/fontello.woff?11878820') format('woff'),
+ url('../font/fontello.ttf?11878820') format('truetype'),
+ url('../font/fontello.svg?11878820#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
@@ -15,7 +15,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'fontello';
- src: url('../font/fontello.svg?72648396#fontello') format('svg');
+ src: url('../font/fontello.svg?11878820#fontello') format('svg');
}
}
*/
@@ -80,6 +80,8 @@
.icon-adjust:before { content: '\e816'; } /* '' */
.icon-edit:before { content: '\e817'; } /* '' */
.icon-pencil:before { content: '\e818'; } /* '' */
+.icon-verified:before { content: '\e819'; } /* '' */
+.icon-wrench:before { content: '\e81a'; } /* '' */
.icon-spin3:before { content: '\e832'; } /* '' */
.icon-spin4:before { content: '\e834'; } /* '' */
.icon-link-ext:before { content: '\f08e'; } /* '' */
diff --git a/static/font/demo.html b/static/font/demo.html
old mode 100644
new mode 100755
index 159dfd4a..1a1147af
--- a/static/font/demo.html
+++ b/static/font/demo.html
@@ -229,11 +229,11 @@ body {
}
@font-face {
font-family: 'fontello';
- src: url('./font/fontello.eot?23081587');
- src: url('./font/fontello.eot?23081587#iefix') format('embedded-opentype'),
- url('./font/fontello.woff?23081587') format('woff'),
- url('./font/fontello.ttf?23081587') format('truetype'),
- url('./font/fontello.svg?23081587#fontello') format('svg');
+ src: url('./font/fontello.eot?60799712');
+ src: url('./font/fontello.eot?60799712#iefix') format('embedded-opentype'),
+ url('./font/fontello.woff?60799712') format('woff'),
+ url('./font/fontello.ttf?60799712') format('truetype'),
+ url('./font/fontello.svg?60799712#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
@@ -335,25 +335,29 @@ body {
icon-pencil0xe818
+
icon-verified0xe819
+
icon-wrench0xe81a
icon-spin30xe832
+
+
icon-spin40xe834
icon-link-ext0xf08e
-
-
icon-link-ext-alt0xf08f
icon-menu0xf0c9
+
+
icon-mail-alt0xf0e0
icon-comment-empty0xf0e5
-
-
icon-bell-alt0xf0f3
icon-plus-squared0xf0fe
-
icon-reply0xf112
-
icon-lock-open-alt0xf13e
+
icon-reply0xf112
+
icon-lock-open-alt0xf13e
icon-play-circled0xf144
icon-thumbs-up-alt0xf164
+
+
icon-binoculars0xf1e5
icon-user-plus0xf234
diff --git a/static/font/font/fontello.eot b/static/font/font/fontello.eot
index 646a80b0..b9cdfcb5 100755
Binary files a/static/font/font/fontello.eot and b/static/font/font/fontello.eot differ
diff --git a/static/font/font/fontello.svg b/static/font/font/fontello.svg
index 04869290..0e460ea5 100755
--- a/static/font/font/fontello.svg
+++ b/static/font/font/fontello.svg
@@ -56,6 +56,10 @@
+
+
+
+
diff --git a/static/font/font/fontello.ttf b/static/font/font/fontello.ttf
index 90784968..f1b9f19d 100755
Binary files a/static/font/font/fontello.ttf and b/static/font/font/fontello.ttf differ
diff --git a/static/font/font/fontello.woff b/static/font/font/fontello.woff
index 95077a64..141abc65 100755
Binary files a/static/font/font/fontello.woff and b/static/font/font/fontello.woff differ
diff --git a/static/font/font/fontello.woff2 b/static/font/font/fontello.woff2
index 7d9c653a..efed5cf7 100755
Binary files a/static/font/font/fontello.woff2 and b/static/font/font/fontello.woff2 differ
diff --git a/test/fixtures/mastoapi.json b/test/fixtures/mastoapi.json
index 858d7a0d..887fb83e 100644
--- a/test/fixtures/mastoapi.json
+++ b/test/fixtures/mastoapi.json
@@ -58,7 +58,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639",
"url": "https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -127,7 +130,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/6634d32b-96a8-4852-a3db-ac8730715779",
"url": "https://shigusegubu.club/objects/6634d32b-96a8-4852-a3db-ac8730715779",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -250,7 +256,10 @@
"tags": [],
"uri": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b",
"url": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
},
"reblogged": false,
"reblogs_count": 0,
@@ -260,7 +269,10 @@
"tags": [],
"uri": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b",
"url": "https://pleroma.soykaf.com/objects/bf7e43d4-5048-4176-8519-58e3e1014f8b",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -329,7 +341,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/0f963ca1-a263-41ca-a43c-b5d26d0a08e9",
"url": "https://shigusegubu.club/objects/0f963ca1-a263-41ca-a43c-b5d26d0a08e9",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -390,7 +405,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/3f809bd8-656f-4a29-81d4-80eed6916eb0",
"url": "https://shigusegubu.club/objects/3f809bd8-656f-4a29-81d4-80eed6916eb0",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -516,7 +534,10 @@
}],
"uri": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note",
"url": "https://social.super-niche.club/notice/2353002",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
},
"reblogged": false,
"reblogs_count": 0,
@@ -529,7 +550,10 @@
}],
"uri": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note",
"url": "tag:social.super-niche.club,2019-01-17:noticeId=2353002:objectType=note",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -657,7 +681,10 @@
"tags": [],
"uri": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab",
"url": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
},
"reblogged": false,
"reblogs_count": 0,
@@ -667,7 +694,10 @@
"tags": [],
"uri": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab",
"url": "https://miniwa.moe/objects/448e2944-0ecd-457f-92c3-cb454f2b0fab",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -733,7 +763,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/38b1bc44-15d8-40dd-b1aa-937e0ff4a86d",
"url": "https://shigusegubu.club/objects/38b1bc44-15d8-40dd-b1aa-937e0ff4a86d",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -794,7 +827,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/fbff5da4-a517-42a9-bca9-17cae8cf2542",
"url": "https://shigusegubu.club/objects/fbff5da4-a517-42a9-bca9-17cae8cf2542",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -850,7 +886,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/4007d659-27c6-4577-be10-fd134f5e4e7e",
"url": "https://shigusegubu.club/objects/4007d659-27c6-4577-be10-fd134f5e4e7e",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -906,7 +945,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/59912d51-1cc6-4dc7-828c-f167e6c8b391",
"url": "https://shigusegubu.club/objects/59912d51-1cc6-4dc7-828c-f167e6c8b391",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -962,7 +1004,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/62690bce-3f49-4047-9c8e-8941f2f79e10",
"url": "https://shigusegubu.club/objects/62690bce-3f49-4047-9c8e-8941f2f79e10",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -1023,7 +1068,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/818f3dd0-2ff8-4def-a170-e4d4c405f387",
"url": "https://shigusegubu.club/objects/818f3dd0-2ff8-4def-a170-e4d4c405f387",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -1084,7 +1132,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/0783a193-c097-488d-8944-47df9372cd6e",
"url": "https://shigusegubu.club/objects/0783a193-c097-488d-8944-47df9372cd6e",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -1145,7 +1196,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/145d5252-7b8e-467d-9f36-1db0818f452f",
"url": "https://shigusegubu.club/objects/145d5252-7b8e-467d-9f36-1db0818f452f",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -1252,7 +1306,10 @@
"tags": [],
"uri": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a",
"url": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
},
"reblogged": false,
"reblogs_count": 0,
@@ -1262,7 +1319,10 @@
"tags": [],
"uri": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a",
"url": "https://pleroma.site/objects/3076c055-0e34-4cf9-86ca-2d148b9b694a",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -1323,7 +1383,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/d4eb7c46-02f9-4b1f-83af-926cefa21f33",
"url": "https://shigusegubu.club/objects/d4eb7c46-02f9-4b1f-83af-926cefa21f33",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -1446,7 +1509,10 @@
"tags": [],
"uri": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733",
"url": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
},
"reblogged": false,
"reblogs_count": 0,
@@ -1456,7 +1522,10 @@
"tags": [],
"uri": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733",
"url": "https://pleroma.soykaf.com/objects/338b6bd2-3c2d-40fe-93a3-28b688782733",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -1517,7 +1586,10 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/f472f4ed-8b0b-492f-9d53-d69eda79629d",
"url": "https://shigusegubu.club/objects/f472f4ed-8b0b-492f-9d53-d69eda79629d",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}, {
"account": {
"acct": "hj",
@@ -1578,5 +1650,8 @@
"tags": [],
"uri": "https://shigusegubu.club/objects/d6fb4fd2-1f6a-4446-a1a6-5edd34050096",
"url": "https://shigusegubu.club/objects/d6fb4fd2-1f6a-4446-a1a6-5edd34050096",
- "visibility": "public"
+ "visibility": "public",
+ "pleroma": {
+ "local": true
+ }
}]
diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
index 2b0b0d6d..bae890f8 100644
--- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
+++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
@@ -129,7 +129,10 @@ const makeMockStatusMasto = (overrides = {}) => {
tags: [],
uri: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639',
url: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639',
- visibility: 'public'
+ visibility: 'public',
+ pleroma: {
+ local: true
+ }
}, overrides)
}
diff --git a/test/unit/specs/services/notification_utils/notification_utils.spec.js b/test/unit/specs/services/notification_utils/notification_utils.spec.js
index e945459e..1baa5fc9 100644
--- a/test/unit/specs/services/notification_utils/notification_utils.spec.js
+++ b/test/unit/specs/services/notification_utils/notification_utils.spec.js
@@ -9,14 +9,17 @@ describe('NotificationUtils', () => {
notifications: {
data: [
{
+ id: 1,
action: { id: '1' },
type: 'like'
},
{
+ id: 2,
action: { id: '2' },
type: 'mention'
},
{
+ id: 3,
action: { id: '3' },
type: 'repeat'
}
@@ -35,10 +38,12 @@ describe('NotificationUtils', () => {
const expected = [
{
action: { id: '3' },
+ id: 3,
type: 'repeat'
},
{
action: { id: '1' },
+ id: 1,
type: 'like'
}
]
diff --git a/yarn.lock b/yarn.lock
index 98992dba..489bd9f3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6097,6 +6097,10 @@ pkg-dir@^3.0.0:
dependencies:
find-up "^3.0.0"
+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"
@@ -8068,6 +8072,10 @@ uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
+v-click-outside@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/v-click-outside/-/v-click-outside-2.1.1.tgz#5af80b68a1c82eac89c597890434fa3994b42ed1"
+
validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
@@ -8141,6 +8149,10 @@ vue-hot-reload-api@^2.2.0:
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.3.tgz#2756f46cb3258054c5f4723de8ae7e87302a1ccf"
integrity sha512-KmvZVtmM26BQOMK1rwUZsrqxEGeKiYSZGA7SNWE6uExx8UX/cj9hq2MRV/wWC3Cq6AoeDGk57rL9YMFRel/q+g==
+vue-hot-reload-api@^2.0.11:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.1.tgz#b2d3d95402a811602380783ea4f566eb875569a2"
+
vue-i18n@^7.3.2:
version "7.8.1"
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-7.8.1.tgz#2ce4b6efde679a1e05ddb5d907bfc1bc218803b2"
@@ -8165,6 +8177,12 @@ vue-loader@^14.0.0:
vue-style-loader "^4.0.1"
vue-template-es2015-compiler "^1.6.0"
+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"