Compare commits

...

17 commits

Author SHA1 Message Date
lain
63088deb2e User Profile: Reduxify 2020-06-30 15:23:40 +02:00
lain
1bfe811fc7 Chat Panel: Actually reduxify. 2020-06-30 15:04:32 +02:00
lain
22433cab90 Chat Panel: Reduxify. 2020-06-30 15:04:07 +02:00
lain
3ec664ce02 Mutes and Blocks: Reduxify. 2020-06-30 15:02:27 +02:00
lain
2e131e5b22 Profile Tab: Reduxify. 2020-06-30 14:57:10 +02:00
lain
30149f55f4 Data import, user panel, who to follow: Reduxify. 2020-06-30 14:50:33 +02:00
lain
9b437c4e56 Basic user card: Reduxify. 2020-06-30 14:43:56 +02:00
lain
2d9ab01575 User Cards: Reduxify. 2020-06-30 14:35:11 +02:00
lain
c4d7331fd6 User Card: redux. 2020-06-30 14:06:50 +02:00
lain
c1b28879f9 Media Modal: Fix mimetype. 2020-06-30 14:06:23 +02:00
lain
fe30bd6d04 Merge branch 'develop' of git.pleroma.social:pleroma/pleroma-fe into redux 2020-06-30 13:41:41 +02:00
lain
145b4e1e52 Notifications: Use notifications natively. 2020-06-25 16:06:17 +02:00
lain
7d5c3e5db0 Notification: Even more reducing. 2020-06-25 15:55:12 +02:00
lain
70db485a58 Notifications: More reduxification. 2020-06-25 15:32:37 +02:00
lain
6074f16f9b Notifications: Reduxify. 2020-06-25 15:09:56 +02:00
lain
e3cf82b3be Yarn upgrade. 2020-06-25 14:35:52 +02:00
lain
20ada31498 Normalizing: Natively use attachments. 2020-06-25 09:51:26 +02:00
30 changed files with 3211 additions and 2093 deletions

1
.tool-versions Normal file
View file

@ -0,0 +1 @@
nodejs 12.18.0

View file

@ -35,7 +35,6 @@
"vuex": "^3.0.1" "vuex": "^3.0.1"
}, },
"devDependencies": { "devDependencies": {
"karma-mocha-reporter": "^2.2.1",
"@babel/core": "^7.7.5", "@babel/core": "^7.7.5",
"@babel/plugin-transform-runtime": "^7.7.6", "@babel/plugin-transform-runtime": "^7.7.6",
"@babel/preset-env": "^7.7.6", "@babel/preset-env": "^7.7.6",
@ -79,6 +78,7 @@
"karma-coverage": "^1.1.1", "karma-coverage": "^1.1.1",
"karma-firefox-launcher": "^1.1.0", "karma-firefox-launcher": "^1.1.0",
"karma-mocha": "^1.2.0", "karma-mocha": "^1.2.0",
"karma-mocha-reporter": "^2.2.1",
"karma-sinon-chai": "^2.0.2", "karma-sinon-chai": "^2.0.2",
"karma-sourcemap-loader": "^0.3.7", "karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.26", "karma-spec-reporter": "0.0.26",

View file

@ -20,7 +20,7 @@ const Attachment = {
hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw, hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw,
preloadImage: this.$store.getters.mergedConfig.preloadImage, preloadImage: this.$store.getters.mergedConfig.preloadImage,
loading: false, loading: false,
img: fileTypeService.fileType(this.attachment.mimetype) === 'image' && document.createElement('img'), img: fileTypeService.fileType(this.attachment.pleroma.mime_type) === 'image' && document.createElement('img'),
modalOpen: false, modalOpen: false,
showHidden: false showHidden: false
} }
@ -37,7 +37,7 @@ const Attachment = {
return this.$store.state.instance.mediaProxyAvailable ? '' : 'no-referrer' return this.$store.state.instance.mediaProxyAvailable ? '' : 'no-referrer'
}, },
type () { type () {
return fileTypeService.fileType(this.attachment.mimetype) return fileTypeService.fileType(this.attachment.pleroma.mime_type)
}, },
hidden () { hidden () {
return this.nsfw && this.hideNsfwLocal && !this.showHidden return this.nsfw && this.hideNsfwLocal && !this.showHidden

View file

@ -56,7 +56,7 @@
> >
<StillImage <StillImage
:referrerpolicy="referrerpolicy" :referrerpolicy="referrerpolicy"
:mimetype="attachment.mimetype" :mimetype="attachment.pleroma.mime_type"
:src="attachment.large_thumb_url || attachment.url" :src="attachment.large_thumb_url || attachment.url"
:image-load-handler="onImageLoad" :image-load-handler="onImageLoad"
/> />

View file

@ -20,7 +20,7 @@ const BasicUserCard = {
this.userExpanded = !this.userExpanded this.userExpanded = !this.userExpanded
}, },
userProfileLink (user) { userProfileLink (user) {
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) return generateProfileLink(user.redux.id, user.redux.acct, this.$store.state.instance.restrictedNicknames)
} }
} }
} }

View file

@ -12,7 +12,7 @@
class="basic-user-card-expanded-content" class="basic-user-card-expanded-content"
> >
<UserCard <UserCard
:user-id="user.id" :user-id="user.redux.id"
:rounded="true" :rounded="true"
:bordered="true" :bordered="true"
/> />
@ -22,27 +22,27 @@
class="basic-user-card-collapsed-content" class="basic-user-card-collapsed-content"
> >
<div <div
:title="user.name" :title="user.redux.display_name"
class="basic-user-card-user-name" class="basic-user-card-user-name"
> >
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<span <span
v-if="user.name_html" v-if="user.redux.display_name_html"
class="basic-user-card-user-name-value" class="basic-user-card-user-name-value"
v-html="user.name_html" v-html="user.redux.display_name_html"
/> />
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
<span <span
v-else v-else
class="basic-user-card-user-name-value" class="basic-user-card-user-name-value"
>{{ user.name }}</span> >{{ user.redux.display_name }}</span>
</div> </div>
<div> <div>
<router-link <router-link
class="basic-user-card-screen-name" class="basic-user-card-screen-name"
:to="userProfileLink(user)" :to="userProfileLink(user)"
> >
@{{ user.screen_name }} @{{ user.redux.acct }}
</router-link> </router-link>
</div> </div>
<slot /> <slot />

View file

@ -23,7 +23,7 @@ const chatPanel = {
this.collapsed = !this.collapsed this.collapsed = !this.collapsed
}, },
userProfileLink (user) { userProfileLink (user) {
return generateProfileLink(user.id, user.username, this.$store.state.instance.restrictedNicknames) return generateProfileLink(user.redux.id, user.redux.acct, this.$store.state.instance.restrictedNicknames)
} }
} }
} }

View file

@ -14,7 +14,7 @@ const FollowCard = {
}, },
computed: { computed: {
isMe () { isMe () {
return this.$store.state.users.currentUser.id === this.user.id return this.$store.state.users.currentUser.id === this.user.redux.id
}, },
loggedIn () { loggedIn () {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser

View file

@ -27,7 +27,7 @@ const MediaModal = {
return this.media.length > 1 return this.media.length > 1
}, },
type () { type () {
return this.currentMedia ? fileTypeService.fileType(this.currentMedia.mimetype) : null return this.currentMedia ? fileTypeService.fileType(this.currentMedia.pleroma.mime_type) : null
} }
}, },
created () { created () {

View file

@ -31,7 +31,7 @@ const Notification = {
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
}, },
getUser (notification) { getUser (notification) {
return this.$store.state.users.usersObject[notification.from_profile.id] return this.$store.state.users.usersObject[notification.account.id]
}, },
toggleMute () { toggleMute () {
this.unmuted = !this.unmuted this.unmuted = !this.unmuted
@ -57,15 +57,15 @@ const Notification = {
}, },
computed: { computed: {
userClass () { userClass () {
return highlightClass(this.notification.from_profile) return highlightClass(this.notification.account)
}, },
userStyle () { userStyle () {
const highlight = this.$store.getters.mergedConfig.highlight const highlight = this.$store.getters.mergedConfig.highlight
const user = this.notification.from_profile const user = this.notification.account
return highlightStyle(highlight[user.screen_name]) return highlightStyle(highlight[user.screen_name])
}, },
user () { user () {
return this.$store.getters.findUser(this.notification.from_profile.id) return this.$store.getters.findUser(this.notification.account.id)
}, },
userProfileLink () { userProfileLink () {
return this.generateUserProfileLink(this.user) return this.generateUserProfileLink(this.user)
@ -80,7 +80,7 @@ const Notification = {
return this.$store.getters.relationship(this.user.id).muting return this.$store.getters.relationship(this.user.id).muting
}, },
isStatusNotification () { isStatusNotification () {
return isStatusNotification(this.notification.type) return (this.notification.type)
} }
} }
} }

View file

@ -11,7 +11,7 @@
> >
<small> <small>
<router-link :to="userProfileLink"> <router-link :to="userProfileLink">
{{ notification.from_profile.screen_name }} {{ notification.account.redux.acct }}
</router-link> </router-link>
</small> </small>
<a <a
@ -28,13 +28,13 @@
> >
<a <a
class="avatar-container" class="avatar-container"
:href="notification.from_profile.statusnet_profile_url" :href="notification.account.redux.url"
@click.stop.prevent.capture="toggleUserExpanded" @click.stop.prevent.capture="toggleUserExpanded"
> >
<UserAvatar <UserAvatar
:compact="true" :compact="true"
:better-shadow="betterShadow" :better-shadow="betterShadow"
:user="notification.from_profile" :user="notification.account"
/> />
</a> </a>
<div class="notification-right"> <div class="notification-right">
@ -48,22 +48,22 @@
<div class="name-and-action"> <div class="name-and-action">
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<bdi <bdi
v-if="!!notification.from_profile.name_html" v-if="!!notification.account.name_html"
class="username" class="username"
:title="'@'+notification.from_profile.screen_name" :title="'@'+notification.account.screen_name"
v-html="notification.from_profile.name_html" v-html="notification.account.name_html"
/> />
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
<span <span
v-else v-else
class="username" class="username"
:title="'@'+notification.from_profile.screen_name" :title="'@'+notification.account.redux.acct"
>{{ notification.from_profile.name }}</span> >{{ notification.account.display_name }}</span>
<span v-if="notification.type === 'like'"> <span v-if="notification.type === 'favourite'">
<i class="fa icon-star lit" /> <i class="fa icon-star lit" />
<small>{{ $t('notifications.favorited_you') }}</small> <small>{{ $t('notifications.favorited_you') }}</small>
</span> </span>
<span v-if="notification.type === 'repeat'"> <span v-if="notification.type === 'reblog'">
<i <i
class="fa icon-retweet lit" class="fa icon-retweet lit"
:title="$t('tool_tip.repeat')" :title="$t('tool_tip.repeat')"
@ -130,7 +130,7 @@
:to="userProfileLink" :to="userProfileLink"
class="follow-name" class="follow-name"
> >
@{{ notification.from_profile.screen_name }} @{{ notification.account.redux.acct }}
</router-link> </router-link>
<div <div
v-if="notification.type === 'follow_request'" v-if="notification.type === 'follow_request'"
@ -153,13 +153,13 @@
class="move-text" class="move-text"
> >
<router-link :to="targetUserProfileLink"> <router-link :to="targetUserProfileLink">
@{{ notification.target.screen_name }} @{{ notification.target.redux.acct }}
</router-link> </router-link>
</div> </div>
<template v-else> <template v-else>
<status-content <status-content
class="faint" class="faint"
:status="notification.action" :status="notification.status"
/> />
</template> </template>
</div> </div>

View file

@ -35,7 +35,7 @@
v-for="notification in notificationsToDisplay" v-for="notification in notificationsToDisplay"
:key="notification.id" :key="notification.id"
class="notification" class="notification"
:class="{&quot;unseen&quot;: !minimalMode && !notification.seen}" :class="{&quot;unseen&quot;: !minimalMode && !notification.pleroma.is_seen}"
> >
<div class="notification-overlay" /> <div class="notification-overlay" />
<notification :notification="notification" /> <notification :notification="notification" />

View file

@ -51,12 +51,12 @@ const DataImportExportTab = {
// Get addresses // Get addresses
return users.map((user) => { return users.map((user) => {
// check is it's a local user // check is it's a local user
if (user && user.is_local) { if (user && user.redux.is_local) {
// append the instance address // append the instance address
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
return user.screen_name + '@' + location.hostname return user.redux.acct + '@' + location.hostname
} }
return user.screen_name return user.redux.acct
}).join('\n') }).join('\n')
} }
} }

View file

@ -80,12 +80,12 @@ const MutesAndBlocks = {
// Get addresses // Get addresses
return users.map((user) => { return users.map((user) => {
// check is it's a local user // check is it's a local user
if (user && user.is_local) { if (user && user.redux.is_local) {
// append the instance address // append the instance address
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
return user.screen_name + '@' + location.hostname return user.redux.acct + '@' + location.hostname
} }
return user.screen_name return user.redux.acct
}).join('\n') }).join('\n')
}, },
activateTab (tabName) { activateTab (tabName) {
@ -94,13 +94,13 @@ const MutesAndBlocks = {
filterUnblockedUsers (userIds) { filterUnblockedUsers (userIds) {
return reject(userIds, (userId) => { return reject(userIds, (userId) => {
const relationship = this.$store.getters.relationship(this.userId) const relationship = this.$store.getters.relationship(this.userId)
return relationship.blocking || userId === this.user.id return relationship.blocking || userId === this.user.redux.id
}) })
}, },
filterUnMutedUsers (userIds) { filterUnMutedUsers (userIds) {
return reject(userIds, (userId) => { return reject(userIds, (userId) => {
const relationship = this.$store.getters.relationship(this.userId) const relationship = this.$store.getters.relationship(this.userId)
return relationship.muting || userId === this.user.id return relationship.muting || userId === this.user.redux.id
}) })
}, },
queryUserIds (query) { queryUserIds (query) {

View file

@ -102,8 +102,8 @@ const ProfileTab = {
show_role: this.showRole show_role: this.showRole
/* eslint-enable camelcase */ /* eslint-enable camelcase */
} }).then((user) => { } }).then((user) => {
this.newFields.splice(user.fields.length) this.newFields.splice(user.redux.fields.length)
merge(this.newFields, user.fields) merge(this.newFields, user.redux.fields)
this.$store.commit('addNewUsers', [user]) this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user) this.$store.commit('setCurrentUser', user)
}) })

View file

@ -163,7 +163,7 @@
</p> </p>
<p>{{ $t('settings.current_avatar') }}</p> <p>{{ $t('settings.current_avatar') }}</p>
<img <img
:src="user.profile_image_url_original" :src="user.redux.avatar"
class="current-avatar" class="current-avatar"
> >
<p>{{ $t('settings.set_new_avatar') }}</p> <p>{{ $t('settings.set_new_avatar') }}</p>
@ -186,7 +186,7 @@
<h2>{{ $t('settings.profile_banner') }}</h2> <h2>{{ $t('settings.profile_banner') }}</h2>
<p>{{ $t('settings.current_profile_banner') }}</p> <p>{{ $t('settings.current_profile_banner') }}</p>
<img <img
:src="user.cover_photo" :src="user.redux.header"
class="banner" class="banner"
> >
<p>{{ $t('settings.set_new_profile_banner') }}</p> <p>{{ $t('settings.set_new_profile_banner') }}</p>

View file

@ -16,7 +16,7 @@ const UserAvatar = {
}, },
computed: { computed: {
imgSrc () { imgSrc () {
return this.showPlaceholder ? '/images/avi.png' : this.user.profile_image_url_original return this.showPlaceholder ? '/images/avi.png' : this.user.redux.avatar
} }
}, },
methods: { methods: {

View file

@ -18,7 +18,7 @@ export default {
} }
}, },
created () { created () {
this.$store.dispatch('fetchUserRelationship', this.user.id) this.$store.dispatch('fetchUserRelationship', this.user.redux.id)
}, },
computed: { computed: {
user () { user () {
@ -38,61 +38,61 @@ export default {
return { return {
backgroundImage: [ backgroundImage: [
`linear-gradient(to bottom, var(--profileTint), var(--profileTint))`, `linear-gradient(to bottom, var(--profileTint), var(--profileTint))`,
`url(${this.user.cover_photo})` `url(${this.user.redux.header})`
].join(', ') ].join(', ')
} }
}, },
isOtherUser () { isOtherUser () {
return this.user.id !== this.$store.state.users.currentUser.id return this.user.redux.id !== this.$store.state.users.currentUser.id
}, },
subscribeUrl () { subscribeUrl () {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
const serverUrl = new URL(this.user.statusnet_profile_url) const serverUrl = new URL(this.user.redux.url)
return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus` return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
}, },
loggedIn () { loggedIn () {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
dailyAvg () { dailyAvg () {
const days = Math.ceil((new Date() - new Date(this.user.created_at)) / (60 * 60 * 24 * 1000)) const days = Math.ceil((new Date() - new Date(this.user.redux.created_at)) / (60 * 60 * 24 * 1000))
return Math.round(this.user.statuses_count / days) return Math.round(this.user.redux.statuses_count / days)
}, },
userHighlightType: { userHighlightType: {
get () { get () {
const data = this.$store.getters.mergedConfig.highlight[this.user.screen_name] const data = this.$store.getters.mergedConfig.highlight[this.user.redux.acct]
return (data && data.type) || 'disabled' return (data && data.type) || 'disabled'
}, },
set (type) { set (type) {
const data = this.$store.getters.mergedConfig.highlight[this.user.screen_name] const data = this.$store.getters.mergedConfig.highlight[this.user.redux.acct]
if (type !== 'disabled') { if (type !== 'disabled') {
this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: (data && data.color) || '#FFFFFF', type }) this.$store.dispatch('setHighlight', { user: this.user.redux.acct, color: (data && data.color) || '#FFFFFF', type })
} else { } else {
this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: undefined }) this.$store.dispatch('setHighlight', { user: this.user.redux.acct, color: undefined })
} }
}, },
...mapGetters(['mergedConfig']) ...mapGetters(['mergedConfig'])
}, },
userHighlightColor: { userHighlightColor: {
get () { get () {
const data = this.$store.getters.mergedConfig.highlight[this.user.screen_name] const data = this.$store.getters.mergedConfig.highlight[this.user.redux.acct]
return data && data.color return data && data.color
}, },
set (color) { set (color) {
this.$store.dispatch('setHighlight', { user: this.user.screen_name, color }) this.$store.dispatch('setHighlight', { user: this.user.redux.acct, color })
} }
}, },
visibleRole () { visibleRole () {
const rights = this.user.rights const rights = this.user.redux.pleroma
if (!rights) { return } if (!rights) { return }
const validRole = rights.admin || rights.moderator const validRole = rights.is_admin || rights.is_moderator
const roleTitle = rights.admin ? 'admin' : 'moderator' const roleTitle = rights.is_admin ? 'admin' : 'moderator'
return validRole && roleTitle return validRole && roleTitle
}, },
hideFollowsCount () { hideFollowsCount () {
return this.isOtherUser && this.user.hide_follows_count return this.isOtherUser && this.user.redux.hide_follows_count
}, },
hideFollowersCount () { hideFollowersCount () {
return this.isOtherUser && this.user.hide_followers_count return this.isOtherUser && this.user.redux.hide_followers_count
}, },
...mapGetters(['mergedConfig']) ...mapGetters(['mergedConfig'])
}, },
@ -106,16 +106,16 @@ export default {
}, },
methods: { methods: {
muteUser () { muteUser () {
this.$store.dispatch('muteUser', this.user.id) this.$store.dispatch('muteUser', this.user.redux.id)
}, },
unmuteUser () { unmuteUser () {
this.$store.dispatch('unmuteUser', this.user.id) this.$store.dispatch('unmuteUser', this.user.redux.id)
}, },
subscribeUser () { subscribeUser () {
return this.$store.dispatch('subscribeUser', this.user.id) return this.$store.dispatch('subscribeUser', this.user.redux.id)
}, },
unsubscribeUser () { unsubscribeUser () {
return this.$store.dispatch('unsubscribeUser', this.user.id) return this.$store.dispatch('unsubscribeUser', this.user.redux.id)
}, },
setProfileView (v) { setProfileView (v) {
if (this.switcher) { if (this.switcher) {
@ -133,14 +133,16 @@ export default {
}, },
userProfileLink (user) { userProfileLink (user) {
return generateProfileLink( return generateProfileLink(
user.id, user.screen_name, user.redux.id, user.redux.acct,
this.$store.state.instance.restrictedNicknames this.$store.state.instance.restrictedNicknames
) )
}, },
zoomAvatar () { zoomAvatar () {
const attachment = { const attachment = {
url: this.user.profile_image_url_original, url: this.user.redux.avatar,
mimetype: 'image' pleroma: {
mime_type: 'image'
}
} }
this.$store.dispatch('setMedia', [attachment]) this.$store.dispatch('setMedia', [attachment])
this.$store.dispatch('setCurrent', attachment) this.$store.dispatch('setCurrent', attachment)

View file

@ -37,22 +37,22 @@
<div class="top-line"> <div class="top-line">
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<div <div
v-if="user.name_html" v-if="user.redux.display_name_html"
:title="user.name" :title="user.redux.display_name"
class="user-name" class="user-name"
v-html="user.name_html" v-html="user.redux.display_name_html"
/> />
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
<div <div
v-else v-else
:title="user.name" :title="user.redux.display_name"
class="user-name" class="user-name"
> >
{{ user.name }} {{ user.redux.display_name }}
</div> </div>
<a <a
v-if="isOtherUser && !user.is_local" v-if="isOtherUser && !user.redux.is_local"
:href="user.statusnet_profile_url" :href="user.redux.url"
target="_blank" target="_blank"
> >
<i class="icon-link-ext usersettings" /> <i class="icon-link-ext usersettings" />
@ -68,7 +68,7 @@
class="user-screen-name" class="user-screen-name"
:to="userProfileLink(user)" :to="userProfileLink(user)"
> >
@{{ user.screen_name }} @{{ user.redux.acct }}
</router-link> </router-link>
<template v-if="!hideBio"> <template v-if="!hideBio">
<span <span
@ -78,13 +78,13 @@
{{ visibleRole }} {{ visibleRole }}
</span> </span>
<span <span
v-if="user.bot" v-if="user.redux.bot"
class="alert user-role" class="alert user-role"
> >
bot bot
</span> </span>
</template> </template>
<span v-if="user.locked"><i class="icon icon-lock" /></span> <span v-if="user.redux.locked"><i class="icon icon-lock" /></span>
<span <span
v-if="!mergedConfig.hideUserStats && !hideBio" v-if="!mergedConfig.hideUserStats && !hideBio"
class="dailyAvg" class="dailyAvg"
@ -106,14 +106,14 @@
<!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to --> <!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to -->
<input <input
v-if="userHighlightType !== 'disabled'" v-if="userHighlightType !== 'disabled'"
:id="'userHighlightColorTx'+user.id" :id="'userHighlightColorTx'+user.redux.id"
v-model="userHighlightColor" v-model="userHighlightColor"
class="userHighlightText" class="userHighlightText"
type="text" type="text"
> >
<input <input
v-if="userHighlightType !== 'disabled'" v-if="userHighlightType !== 'disabled'"
:id="'userHighlightColor'+user.id" :id="'userHighlightColor'+user.redux.id"
v-model="userHighlightColor" v-model="userHighlightColor"
class="userHighlightCl" class="userHighlightCl"
type="color" type="color"
@ -123,7 +123,7 @@
class="userHighlightSel select" class="userHighlightSel select"
> >
<select <select
:id="'userHighlightSel'+user.id" :id="'userHighlightSel'+user.redux.id"
v-model="userHighlightType" v-model="userHighlightType"
class="userHighlightSel" class="userHighlightSel"
> >
@ -191,7 +191,7 @@
/> />
</div> </div>
<div <div
v-if="!loggedIn && user.is_local" v-if="!loggedIn && user.redux.is_local"
class="user-interactions" class="user-interactions"
> >
<RemoteFollow :user="user" /> <RemoteFollow :user="user" />
@ -211,36 +211,36 @@
@click.prevent="setProfileView('statuses')" @click.prevent="setProfileView('statuses')"
> >
<h5>{{ $t('user_card.statuses') }}</h5> <h5>{{ $t('user_card.statuses') }}</h5>
<span>{{ user.statuses_count }} <br></span> <span>{{ user.redux.statuses_count }} <br></span>
</div> </div>
<div <div
class="user-count" class="user-count"
@click.prevent="setProfileView('friends')" @click.prevent="setProfileView('friends')"
> >
<h5>{{ $t('user_card.followees') }}</h5> <h5>{{ $t('user_card.followees') }}</h5>
<span>{{ hideFollowsCount ? $t('user_card.hidden') : user.friends_count }}</span> <span>{{ hideFollowsCount ? $t('user_card.hidden') : user.redux.following_count }}</span>
</div> </div>
<div <div
class="user-count" class="user-count"
@click.prevent="setProfileView('followers')" @click.prevent="setProfileView('followers')"
> >
<h5>{{ $t('user_card.followers') }}</h5> <h5>{{ $t('user_card.followers') }}</h5>
<span>{{ hideFollowersCount ? $t('user_card.hidden') : user.followers_count }}</span> <span>{{ hideFollowersCount ? $t('user_card.hidden') : user.redux.followers_count }}</span>
</div> </div>
</div> </div>
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<p <p
v-if="!hideBio && user.description_html" v-if="!hideBio && user.redux.note_html"
class="user-card-bio" class="user-card-bio"
@click.prevent="linkClicked" @click.prevent="linkClicked"
v-html="user.description_html" v-html="user.redux.note_html"
/> />
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
<p <p
v-else-if="!hideBio" v-else-if="!hideBio"
class="user-card-bio" class="user-card-bio"
> >
{{ user.description }} {{ user.redux.note }}
</p> </p>
</div> </div>
</div> </div>

View file

@ -5,7 +5,7 @@ import { mapState } from 'vuex'
const UserPanel = { const UserPanel = {
computed: { computed: {
signedIn () { return this.user }, signedIn () { return this.redux.user },
...mapState({ user: state => state.users.currentUser }) ...mapState({ user: state => state.users.currentUser })
}, },
components: { components: {

View file

@ -12,23 +12,23 @@
rounded="top" rounded="top"
/> />
<div <div
v-if="user.fields_html && user.fields_html.length > 0" v-if="user.redux.fields_html && user.redux.fields_html.length > 0"
class="user-profile-fields" class="user-profile-fields"
> >
<dl <dl
v-for="(field, index) in user.fields_html" v-for="(field, index) in user.redux.fields_html"
:key="index" :key="index"
class="user-profile-field" class="user-profile-field"
> >
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<dt <dt
:title="user.fields_text[index].name" :title="user.redux.fields_text[index].name"
class="user-profile-field-name" class="user-profile-field-name"
@click.prevent="linkClicked" @click.prevent="linkClicked"
v-html="field.name" v-html="field.name"
/> />
<dd <dd
:title="user.fields_text[index].value" :title="user.redux.fields_text[index].value"
class="user-profile-field-value" class="user-profile-field-value"
@click.prevent="linkClicked" @click.prevent="linkClicked"
v-html="field.value" v-html="field.value"
@ -44,7 +44,7 @@
<Timeline <Timeline
key="statuses" key="statuses"
:label="$t('user_card.statuses')" :label="$t('user_card.statuses')"
:count="user.statuses_count" :count="user.redux.statuses_count"
:embedded="true" :embedded="true"
:title="$t('user_profile.timeline_title')" :title="$t('user_profile.timeline_title')"
:timeline="timeline" :timeline="timeline"
@ -57,7 +57,7 @@
v-if="followsTabVisible" v-if="followsTabVisible"
key="followees" key="followees"
:label="$t('user_card.followees')" :label="$t('user_card.followees')"
:disabled="!user.friends_count" :disabled="!user.redux.following_count"
> >
<FriendList :user-id="userId"> <FriendList :user-id="userId">
<template <template
@ -72,7 +72,7 @@
v-if="followersTabVisible" v-if="followersTabVisible"
key="followers" key="followers"
:label="$t('user_card.followers')" :label="$t('user_card.followers')"
:disabled="!user.followers_count" :disabled="!user.redux.followers_count"
> >
<FollowerList :user-id="userId"> <FollowerList :user-id="userId">
<template <template

View file

@ -6,7 +6,7 @@
<div class="panel-body"> <div class="panel-body">
<FollowCard <FollowCard
v-for="user in users" v-for="user in users"
:key="user.id" :key="user.redux.id"
:user="user" :user="user"
class="list-item" class="list-item"
/> />

View file

@ -9,12 +9,12 @@
<div class="who-to-follow"> <div class="who-to-follow">
<p <p
v-for="user in usersToFollow" v-for="user in usersToFollow"
:key="user.id" :key="user.redux.id"
class="who-to-follow-items" class="who-to-follow-items"
> >
<img :src="user.img"> <img :src="user.redux.avatar">
<router-link :to="userProfileLink(user.id, user.name)"> <router-link :to="userProfileLink(user.redux.id, user.redux.display_name)">
{{ user.name }} {{ user.redux.display_name }}
</router-link><br> </router-link><br>
</p> </p>
<p class="who-to-follow-more"> <p class="who-to-follow-more">

View file

@ -21,7 +21,7 @@ const mediaViewer = {
actions: { actions: {
setMedia ({ commit }, attachments) { setMedia ({ commit }, attachments) {
const media = attachments.filter(attachment => { const media = attachments.filter(attachment => {
const type = fileTypeService.fileType(attachment.mimetype) const type = fileTypeService.fileType(attachment.pleroma.mime_type)
return type === 'image' || type === 'video' return type === 'image' || type === 'video'
}) })
commit('setMedia', media) commit('setMedia', media)

View file

@ -13,7 +13,7 @@ import {
omitBy omitBy
} from 'lodash' } from 'lodash'
import { set } from 'vue' import { set } from 'vue'
import { isStatusNotification, prepareNotificationObject } from '../services/notification_utils/notification_utils.js' import { isStatusNotification, prepareNotificationObject, visibleTypes } from '../services/notification_utils/notification_utils.js'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
import { muteWordHits } from '../services/status_parser/status_parser.js' import { muteWordHits } from '../services/status_parser/status_parser.js'
@ -76,17 +76,6 @@ export const prepareStatus = (status) => {
return status return status
} }
const visibleNotificationTypes = (rootState) => {
return [
rootState.config.notificationVisibility.likes && 'like',
rootState.config.notificationVisibility.mentions && 'mention',
rootState.config.notificationVisibility.repeats && 'repeat',
rootState.config.notificationVisibility.follows && 'follow',
rootState.config.notificationVisibility.moves && 'move',
rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reactions'
].filter(_ => _)
}
const mergeOrAdd = (arr, obj, item) => { const mergeOrAdd = (arr, obj, item) => {
const oldItem = obj[item.id] const oldItem = obj[item.id]
@ -323,7 +312,6 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => { const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => {
each(notifications, (notification) => { each(notifications, (notification) => {
if (isStatusNotification(notification.type)) { if (isStatusNotification(notification.type)) {
notification.action = addStatusToGlobalStorage(state, notification.action).item
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
} }
@ -347,7 +335,7 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
const notifObj = prepareNotificationObject(notification, rootGetters.i18n) const notifObj = prepareNotificationObject(notification, rootGetters.i18n)
const reasonsToMuteNotif = ( const reasonsToMuteNotif = (
notification.seen || notification.pleroma.is_seen ||
state.notifications.desktopNotificationSilence || state.notifications.desktopNotificationSilence ||
!visibleNotificationTypes.includes(notification.type) || !visibleNotificationTypes.includes(notification.type) ||
( (
@ -364,8 +352,8 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
setTimeout(desktopNotification.close.bind(desktopNotification), 5000) setTimeout(desktopNotification.close.bind(desktopNotification), 5000)
} }
} }
} else if (notification.seen) { } else if (notification.pleroma.is_seen) {
state.notifications.idStore[notification.id].seen = true state.notifications.idStore[notification.id].pleroma.is_seen = true
} }
}) })
} }
@ -498,12 +486,12 @@ export const mutations = {
}, },
markNotificationsAsSeen (state) { markNotificationsAsSeen (state) {
each(state.notifications.data, (notification) => { each(state.notifications.data, (notification) => {
notification.seen = true notification.pleroma.is_seen = true
}) })
}, },
markSingleNotificationAsSeen (state, { id }) { markSingleNotificationAsSeen (state, { id }) {
const notification = find(state.notifications.data, n => n.id === id) const notification = find(state.notifications.data, n => n.id === id)
if (notification) notification.seen = true if (notification) notification.pleroma.is_seen = true
}, },
dismissNotification (state, { id }) { dismissNotification (state, { id }) {
state.notifications.data = state.notifications.data.filter(n => n.id !== id) state.notifications.data = state.notifications.data.filter(n => n.id !== id)
@ -589,7 +577,7 @@ const statuses = {
commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId }) commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId })
}, },
addNewNotifications ({ rootState, commit, dispatch, rootGetters }, { notifications, older }) { addNewNotifications ({ rootState, commit, dispatch, rootGetters }, { notifications, older }) {
commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older, rootGetters }) commit('addNewNotifications', { visibleNotificationTypes: visibleTypes(rootState), dispatch, notifications, older, rootGetters })
}, },
setError ({ rootState, commit }, { value }) { setError ({ rootState, commit }, { value }) {
commit('setError', { value }) commit('setError', { value })

View file

@ -213,10 +213,7 @@ export const mutations = {
status.user = state.usersObject[status.user.id] status.user = state.usersObject[status.user.id]
}, },
setUserForNotification (state, notification) { setUserForNotification (state, notification) {
if (notification.type !== 'follow') { notification.account = state.usersObject[notification.account.id]
notification.action.user = state.usersObject[notification.action.user.id]
}
notification.from_profile = state.usersObject[notification.from_profile.id]
}, },
setColor (state, { user: { id }, highlighted }) { setColor (state, { user: { id }, highlighted }) {
const user = state.usersObject[id] const user = state.usersObject[id]
@ -419,7 +416,7 @@ const users = {
}) })
}, },
addNewNotifications (store, { notifications }) { addNewNotifications (store, { notifications }) {
const users = map(notifications, 'from_profile') const users = map(notifications, 'account')
const targetUsers = map(notifications, 'target').filter(_ => _) const targetUsers = map(notifications, 'target').filter(_ => _)
const notificationIds = notifications.map(_ => _.id) const notificationIds = notifications.map(_ => _.id)
store.commit('addNewUsers', users) store.commit('addNewUsers', users)

View file

@ -188,27 +188,30 @@ export const parseUser = (data) => {
output.rights = output.rights || {} output.rights = output.rights || {}
output.notification_settings = output.notification_settings || {} output.notification_settings = output.notification_settings || {}
output.redux = data
output.redux.display_name_html = addEmojis(escape(data.display_name), data.emojis)
output.redux.note_html = addEmojis(data.note, data.emojis)
output.redux.fields_html = data.fields.map(field => {
return {
name: addEmojis(field.name, data.emojis),
value: addEmojis(field.value, data.emojis)
}
})
output.redux.fields_text = data.fields.map(field => {
return {
name: unescape(field.name.replace(/<[^>]*>/g, '')),
value: unescape(field.value.replace(/<[^>]*>/g, ''))
}
})
output.redux.is_local = !data.acct.includes('@')
return output return output
} }
export const parseAttachment = (data) => { export const parseAttachment = (data) => {
const output = {} return data
const masto = !data.hasOwnProperty('oembed')
if (masto) {
// Not exactly same...
output.mimetype = data.pleroma ? data.pleroma.mime_type : data.type
output.meta = data.meta // not present in BE yet
output.id = data.id
} else {
output.mimetype = data.mimetype
// output.meta = ??? missing
}
output.url = data.url
output.description = data.description
return output
} }
export const addEmojis = (string, emojis) => { export const addEmojis = (string, emojis) => {
const matchOperatorsRegex = /[|\\{}()[\]^$+*?.-]/g const matchOperatorsRegex = /[|\\{}()[\]^$+*?.-]/g
@ -343,38 +346,12 @@ export const parseStatus = (data) => {
} }
export const parseNotification = (data) => { export const parseNotification = (data) => {
const mastoDict = { const redux = data
'favourite': 'like', redux.account = parseUser(data.account)
'reblog': 'repeat' redux.status = isStatusNotification(data.type) ? parseStatus(data.status) : null
} redux.target = data.type !== 'move' ? null : parseUser(data.target)
const masto = !data.hasOwnProperty('ntype')
const output = {}
if (masto) { return redux
output.type = mastoDict[data.type] || data.type
output.seen = data.pleroma.is_seen
output.status = isStatusNotification(output.type) ? parseStatus(data.status) : null
output.action = output.status // TODO: Refactor, this is unneeded
output.target = output.type !== 'move'
? null
: parseUser(data.target)
output.from_profile = parseUser(data.account)
output.emoji = data.emoji
} else {
const parsedNotice = parseStatus(data.notice)
output.type = data.ntype
output.seen = Boolean(data.is_seen)
output.status = output.type === 'like'
? parseStatus(data.notice.favorited_status)
: parsedNotice
output.action = parsedNotice
output.from_profile = parseUser(data.from_profile)
}
output.created_at = new Date(data.created_at)
output.id = parseInt(data.id)
return output
} }
const isNsfw = (status) => { const isNsfw = (status) => {

View file

@ -22,7 +22,7 @@ const fileType = mimetype => {
} }
const fileMatchesSomeType = (types, file) => const fileMatchesSomeType = (types, file) =>
types.some(type => fileType(file.mimetype) === type) types.some(type => fileType(file.pleroma.mime_type) === type)
const fileTypeService = { const fileTypeService = {
fileType, fileType,

View file

@ -2,17 +2,17 @@ import { filter, sortBy, includes } from 'lodash'
export const notificationsFromStore = store => store.state.statuses.notifications.data export const notificationsFromStore = store => store.state.statuses.notifications.data
export const visibleTypes = store => ([ export const visibleTypes = state => ([
store.state.config.notificationVisibility.likes && 'like', state.config.notificationVisibility.likes && 'favourite',
store.state.config.notificationVisibility.mentions && 'mention', state.config.notificationVisibility.mentions && 'mention',
store.state.config.notificationVisibility.repeats && 'repeat', state.config.notificationVisibility.repeats && 'reblog',
store.state.config.notificationVisibility.follows && 'follow', state.config.notificationVisibility.follows && 'follow',
store.state.config.notificationVisibility.followRequest && 'follow_request', state.config.notificationVisibility.followRequest && 'follow_request',
store.state.config.notificationVisibility.moves && 'move', state.config.notificationVisibility.moves && 'move',
store.state.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction' state.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction'
].filter(_ => _)) ].filter(_ => _))
const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction'] const statusNotifications = ['favourite', 'mention', 'reblog', 'pleroma:emoji_reaction']
export const isStatusNotification = (type) => includes(statusNotifications, type) export const isStatusNotification = (type) => includes(statusNotifications, type)
@ -35,29 +35,29 @@ const sortById = (a, b) => {
export const filteredNotificationsFromStore = (store, types) => { export const filteredNotificationsFromStore = (store, types) => {
// map is just to clone the array since sort mutates it and it causes some issues // map is just to clone the array since sort mutates it and it causes some issues
let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById) let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById)
sortedNotifications = sortBy(sortedNotifications, 'seen') sortedNotifications = sortBy(sortedNotifications, 'pleroma.is_seen')
return sortedNotifications.filter( return sortedNotifications.filter(
(notification) => (types || visibleTypes(store)).includes(notification.type) (notification) => (types || visibleTypes(store.state)).includes(notification.type)
) )
} }
export const unseenNotificationsFromStore = store => export const unseenNotificationsFromStore = store =>
filter(filteredNotificationsFromStore(store), ({ seen }) => !seen) filter(filteredNotificationsFromStore(store), ({ pleroma }) => !pleroma.is_seen)
export const prepareNotificationObject = (notification, i18n) => { export const prepareNotificationObject = (notification, i18n) => {
const notifObj = { const notifObj = {
tag: notification.id tag: notification.id
} }
const status = notification.status const status = notification.status
const title = notification.from_profile.name const title = notification.account.name
notifObj.title = title notifObj.title = title
notifObj.icon = notification.from_profile.profile_image_url notifObj.icon = notification.account.profile_image_url
let i18nString let i18nString
switch (notification.type) { switch (notification.type) {
case 'like': case 'favourite':
i18nString = 'favorited_you' i18nString = 'favorited_you'
break break
case 'repeat': case 'reblog':
i18nString = 'repeated_you' i18nString = 'repeated_you'
break break
case 'follow': case 'follow':
@ -81,7 +81,7 @@ export const prepareNotificationObject = (notification, i18n) => {
// Shows first attached non-nsfw image, if any. Should add configuration for this somehow... // Shows first attached non-nsfw image, if any. Should add configuration for this somehow...
if (status && status.attachments && status.attachments.length > 0 && !status.nsfw && if (status && status.attachments && status.attachments.length > 0 && !status.nsfw &&
status.attachments[0].mimetype.startsWith('image/')) { status.attachments[0].pleroma.mime_type.startsWith('image/')) {
notifObj.image = status.attachments[0].url notifObj.image = status.attachments[0].url
} }

4951
yarn.lock

File diff suppressed because it is too large Load diff