Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
pleroma-fe
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Your New SJW Waifu
pleroma-fe
Commits
23d91b78
Commit
23d91b78
authored
Feb 12, 2020
by
Your New SJW Waifu
💬
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'upstream/develop' into neckbeard
parents
6c38e954
96dc297b
Pipeline
#22797
passed with stages
in 9 minutes and 11 seconds
Changes
18
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
236 additions
and
47 deletions
+236
-47
src/App.scss
src/App.scss
+1
-1
src/_variables.scss
src/_variables.scss
+2
-0
src/components/emoji_reactions/emoji_reactions.js
src/components/emoji_reactions/emoji_reactions.js
+44
-4
src/components/emoji_reactions/emoji_reactions.vue
src/components/emoji_reactions/emoji_reactions.vue
+95
-8
src/components/notification/notification.vue
src/components/notification/notification.vue
+7
-0
src/components/notifications/notifications.scss
src/components/notifications/notifications.scss
+4
-0
src/components/react_button/react_button.js
src/components/react_button/react_button.js
+6
-1
src/components/react_button/react_button.vue
src/components/react_button/react_button.vue
+4
-0
src/components/settings/settings.vue
src/components/settings/settings.vue
+10
-0
src/components/status/status.vue
src/components/status/status.vue
+1
-0
src/i18n/en.json
src/i18n/en.json
+4
-1
src/i18n/fi.json
src/i18n/fi.json
+4
-1
src/modules/config.js
src/modules/config.js
+3
-1
src/modules/statuses.js
src/modules/statuses.js
+25
-11
src/services/api/api.service.js
src/services/api/api.service.js
+15
-13
src/services/entity_normalizer/entity_normalizer.service.js
src/services/entity_normalizer/entity_normalizer.service.js
+1
-0
src/services/notification_utils/notification_utils.js
src/services/notification_utils/notification_utils.js
+2
-1
test/unit/specs/modules/statuses.spec.js
test/unit/specs/modules/statuses.spec.js
+8
-5
No files found.
src/App.scss
View file @
23d91b78
...
...
@@ -85,7 +85,7 @@ button {
border-radius
:
$fallback--btnRadius
;
border-radius
:
var
(
--
btnRadius
,
$fallback--btnRadius
);
cursor
:
pointer
;
box-shadow
:
0px
0px
2px
0px
rgba
(
0
,
0
,
0
,
1
)
,
0px
1px
0px
0px
rgba
(
255
,
255
,
255
,
0
.2
)
inset
,
0px
-1px
0px
0px
rgba
(
0
,
0
,
0
,
0
.2
)
inset
;
box-shadow
:
$fallback--buttonShadow
;
box-shadow
:
var
(
--
buttonShadow
);
font-size
:
14px
;
font-family
:
sans-serif
;
...
...
src/_variables.scss
View file @
23d91b78
...
...
@@ -27,3 +27,5 @@ $fallback--tooltipRadius: 5px;
$fallback--avatarRadius
:
4px
;
$fallback--avatarAltRadius
:
10px
;
$fallback--attachmentRadius
:
10px
;
$fallback--buttonShadow
:
0px
0px
2px
0px
rgba
(
0
,
0
,
0
,
1
)
,
0px
1px
0px
0px
rgba
(
255
,
255
,
255
,
0
.2
)
inset
,
0px
-1px
0px
0px
rgba
(
0
,
0
,
0
,
0
.2
)
inset
;
src/components/emoji_reactions/emoji_reactions.js
View file @
23d91b78
import
UserAvatar
from
'
../user_avatar/user_avatar.vue
'
const
EMOJI_REACTION_COUNT_CUTOFF
=
12
const
EmojiReactions
=
{
name
:
'
EmojiReactions
'
,
components
:
{
UserAvatar
},
props
:
[
'
status
'
],
data
:
()
=>
({
showAll
:
false
,
popperOptions
:
{
modifiers
:
{
preventOverflow
:
{
padding
:
{
top
:
50
},
boundariesElement
:
'
viewport
'
}
}
}
}),
computed
:
{
tooManyReactions
()
{
return
this
.
status
.
emoji_reactions
.
length
>
EMOJI_REACTION_COUNT_CUTOFF
},
emojiReactions
()
{
return
this
.
status
.
emoji_reactions
return
this
.
showAll
?
this
.
status
.
emoji_reactions
:
this
.
status
.
emoji_reactions
.
slice
(
0
,
EMOJI_REACTION_COUNT_CUTOFF
)
},
showMoreString
()
{
return
`+
${
this
.
status
.
emoji_reactions
.
length
-
EMOJI_REACTION_COUNT_CUTOFF
}
`
},
accountsForEmoji
()
{
return
this
.
status
.
emoji_reactions
.
reduce
((
acc
,
reaction
)
=>
{
acc
[
reaction
.
name
]
=
reaction
.
accounts
||
[]
return
acc
},
{})
},
loggedIn
()
{
return
!!
this
.
$store
.
state
.
users
.
currentUser
}
},
methods
:
{
toggleShowAll
()
{
this
.
showAll
=
!
this
.
showAll
},
reactedWith
(
emoji
)
{
const
user
=
this
.
$store
.
state
.
users
.
currentUser
const
reaction
=
this
.
status
.
emoji_reactions
.
find
(
r
=>
r
.
emoji
===
emoji
)
return
reaction
.
accounts
&&
reaction
.
accounts
.
find
(
u
=>
u
.
id
===
user
.
id
)
return
this
.
status
.
emoji_reactions
.
find
(
r
=>
r
.
name
===
emoji
).
me
},
fetchEmojiReactionsByIfMissing
()
{
const
hasNoAccounts
=
this
.
status
.
emoji_reactions
.
find
(
r
=>
!
r
.
accounts
)
if
(
hasNoAccounts
)
{
this
.
$store
.
dispatch
(
'
fetchEmojiReactionsBy
'
,
this
.
status
.
id
)
}
},
reactWith
(
emoji
)
{
this
.
$store
.
dispatch
(
'
reactWithEmoji
'
,
{
id
:
this
.
status
.
id
,
emoji
})
...
...
@@ -20,6 +58,8 @@ const EmojiReactions = {
this
.
$store
.
dispatch
(
'
unreactWithEmoji
'
,
{
id
:
this
.
status
.
id
,
emoji
})
},
emojiOnClick
(
emoji
,
event
)
{
if
(
!
this
.
loggedIn
)
return
if
(
this
.
reactedWith
(
emoji
))
{
this
.
unreact
(
emoji
)
}
else
{
...
...
src/components/emoji_reactions/emoji_reactions.vue
View file @
23d91b78
<
template
>
<div
class=
"emoji-reactions"
>
<
button
<
v-popover
v-for=
"(reaction) in emojiReactions"
:key=
"reaction.
emoji
"
class=
"emoji-reaction btn btn-default
"
:class=
"
{ 'picked-reaction': reactedWith(reaction.emoji) }
"
@click="emojiOnClick(reaction.emoji, $event)
"
:key=
"reaction.
name
"
:popper-options=
"popperOptions
"
trigger=
"hover
"
placement=
"top
"
>
<span
class=
"reaction-emoji"
>
{{
reaction
.
emoji
}}
</span>
<span>
{{
reaction
.
count
}}
</span>
</button>
<div
slot=
"popover"
class=
"reacted-users"
>
<div
v-if=
"accountsForEmoji[reaction.name].length"
>
<div
v-for=
"(account) in accountsForEmoji[reaction.name]"
:key=
"account.id"
class=
"reacted-user"
>
<UserAvatar
:user=
"account"
class=
"avatar-small"
:compact=
"true"
/>
<div
class=
"reacted-user-names"
>
<span
class=
"reacted-user-name"
v-html=
"account.name_html"
/>
<span
class=
"reacted-user-screen-name"
>
{{
account
.
screen_name
}}
</span>
</div>
</div>
</div>
<div
v-else
>
<i
class=
"icon-spin4 animate-spin"
/>
</div>
</div>
<button
class=
"emoji-reaction btn btn-default"
:class=
"
{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
@click="emojiOnClick(reaction.name, $event)"
@mouseenter="fetchEmojiReactionsByIfMissing()"
>
<span
class=
"reaction-emoji"
>
{{
reaction
.
name
}}
</span>
<span>
{{
reaction
.
count
}}
</span>
</button>
</v-popover>
<a
v-if=
"tooManyReactions"
@
click=
"toggleShowAll"
class=
"emoji-reaction-expand faint"
href=
'javascript:void(0)'
>
{{
showAll
?
$t
(
'
general.show_less
'
)
:
showMoreString
}}
</a>
</div>
</
template
>
<
script
src=
"./emoji_reactions.js"
></
script
>
...
...
@@ -23,6 +65,31 @@
flex-wrap
:
wrap
;
}
.reacted-users
{
padding
:
0
.5em
;
}
.reacted-user
{
padding
:
0
.25em
;
display
:
flex
;
flex-direction
:
row
;
.reacted-user-names
{
display
:
flex
;
flex-direction
:
column
;
margin-left
:
0
.5em
;
img
{
width
:
1em
;
height
:
1em
;
}
}
.reacted-user-screen-name
{
font-size
:
9px
;
}
}
.emoji-reaction
{
padding
:
0
0
.5em
;
margin-right
:
0
.5em
;
...
...
@@ -38,6 +105,26 @@
&
:focus
{
outline
:
none
;
}
&
.not-clickable
{
cursor
:
default
;
&
:hover
{
box-shadow
:
$fallback--buttonShadow
;
box-shadow
:
var
(
--
buttonShadow
);
}
}
}
.emoji-reaction-expand
{
padding
:
0
0
.5em
;
margin-right
:
0
.5em
;
margin-top
:
0
.5em
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
&
:hover
{
text-decoration
:
underline
;
}
}
.picked-reaction
{
...
...
src/components/notification/notification.vue
View file @
23d91b78
...
...
@@ -78,6 +78,13 @@
<i
class=
"fa icon-arrow-curved lit"
/>
<small>
{{
$t
(
'
notifications.migrated_to
'
)
}}
</small>
</span>
<span
v-if=
"notification.type === 'pleroma:emoji_reaction'"
>
<small>
<i18n
path=
"notifications.reacted_with"
>
<span
class=
"emoji-reaction-emoji"
>
{{
notification
.
emoji
}}
</span>
</i18n>
</small>
</span>
</div>
<div
v-if=
"notification.type === 'follow' || notification.type === 'move'"
...
...
src/components/notifications/notifications.scss
View file @
23d91b78
...
...
@@ -94,6 +94,10 @@
min-width
:
0
;
}
.emoji-reaction-emoji
{
font-size
:
16px
;
}
.notification-details
{
min-width
:
0px
;
word-wrap
:
break-word
;
...
...
src/components/react_button/react_button.js
View file @
23d91b78
...
...
@@ -22,7 +22,12 @@ const ReactButton = {
this
.
showTooltip
=
false
},
addReaction
(
event
,
emoji
)
{
this
.
$store
.
dispatch
(
'
reactWithEmoji
'
,
{
id
:
this
.
status
.
id
,
emoji
})
const
existingReaction
=
this
.
status
.
emoji_reactions
.
find
(
r
=>
r
.
name
===
emoji
)
if
(
existingReaction
&&
existingReaction
.
me
)
{
this
.
$store
.
dispatch
(
'
unreactWithEmoji
'
,
{
id
:
this
.
status
.
id
,
emoji
})
}
else
{
this
.
$store
.
dispatch
(
'
reactWithEmoji
'
,
{
id
:
this
.
status
.
id
,
emoji
})
}
this
.
closeReactionSelect
()
}
},
...
...
src/components/react_button/react_button.vue
View file @
23d91b78
...
...
@@ -54,6 +54,10 @@
.reaction-picker-filter
{
padding
:
0
.5em
;
display
:
flex
;
input
{
flex
:
1
;
}
}
.reaction-picker-divider
{
...
...
src/components/settings/settings.vue
View file @
23d91b78
...
...
@@ -92,6 +92,11 @@
{{ $t('settings.reply_link_preview') }}
</Checkbox>
</li>
<li>
<Checkbox
v-model=
"emojiReactionsOnTimeline"
>
{{ $t('settings.emoji_reactions_on_timeline') }}
</Checkbox>
</li>
</ul>
</div>
...
...
@@ -328,6 +333,11 @@
{
{
$t('settings.notification_visibility_moves')
}
}
</
Checkbox
>
</
li
>
<
li
>
<
Checkbox
v-model
=
"notificationVisibility.emojiReactions"
>
{
{
$t('settings.notification_visibility_emoji_reactions')
}
}
</
Checkbox
>
</
li
>
</
ul
>
</
div
>
<
div
>
...
...
src/components/status/status.vue
View file @
23d91b78
...
...
@@ -369,6 +369,7 @@
</transition>
<EmojiReactions
v-if=
"(mergedConfig.emojiReactionsOnTimeline || isFocused) && (!noHeading && !isPreview)"
:status=
"status"
/>
...
...
src/i18n/en.json
View file @
23d91b78
...
...
@@ -126,7 +126,8 @@
"read"
:
"Read!"
,
"repeated_you"
:
"repeated your status"
,
"no_more_notifications"
:
"No more notifications"
,
"migrated_to"
:
"migrated to"
"migrated_to"
:
"migrated to"
,
"reacted_with"
:
"reacted with {0}"
},
"polls"
:
{
"add_poll"
:
"Add Poll"
,
...
...
@@ -283,6 +284,7 @@
"domain_mutes"
:
"Domains"
,
"avatar_size_instruction"
:
"The recommended minimum size for avatar images is 150x150 pixels."
,
"pad_emoji"
:
"Pad emoji with spaces when adding from picker"
,
"emoji_reactions_on_timeline"
:
"Show emoji reactions on timeline"
,
"export_theme"
:
"Save preset"
,
"filtering"
:
"Filtering"
,
"filtering_explanation"
:
"All statuses containing these words will be muted, one per line"
,
...
...
@@ -331,6 +333,7 @@
"notification_visibility_mentions"
:
"Mentions"
,
"notification_visibility_repeats"
:
"Repeats"
,
"notification_visibility_moves"
:
"User Migrates"
,
"notification_visibility_emoji_reactions"
:
"Reactions"
,
"no_rich_text_description"
:
"Strip rich text formatting from all posts"
,
"no_blocks"
:
"No blocks"
,
"no_mutes"
:
"No mutes"
,
...
...
src/i18n/fi.json
View file @
23d91b78
...
...
@@ -53,7 +53,8 @@
"notifications"
:
"Ilmoitukset"
,
"read"
:
"Lue!"
,
"repeated_you"
:
"toisti viestisi"
,
"no_more_notifications"
:
"Ei enempää ilmoituksia"
"no_more_notifications"
:
"Ei enempää ilmoituksia"
,
"reacted_with"
:
"lisäsi reaktion {0}"
},
"polls"
:
{
"add_poll"
:
"Lisää äänestys"
,
...
...
@@ -140,6 +141,7 @@
"delete_account_description"
:
"Poista tilisi ja viestisi pysyvästi."
,
"delete_account_error"
:
"Virhe poistaessa tiliäsi. Jos virhe jatkuu, ota yhteyttä palvelimesi ylläpitoon."
,
"delete_account_instructions"
:
"Syötä salasanasi vahvistaaksesi tilin poiston."
,
"emoji_reactions_on_timeline"
:
"Näytä emojireaktiot aikajanalla"
,
"export_theme"
:
"Tallenna teema"
,
"filtering"
:
"Suodatus"
,
"filtering_explanation"
:
"Kaikki viestit, jotka sisältävät näitä sanoja, suodatetaan. Yksi sana per rivi."
,
...
...
@@ -183,6 +185,7 @@
"notification_visibility_likes"
:
"Tykkäykset"
,
"notification_visibility_mentions"
:
"Maininnat"
,
"notification_visibility_repeats"
:
"Toistot"
,
"notification_visibility_emoji_reactions"
:
"Reaktiot"
,
"no_rich_text_description"
:
"Älä näytä tekstin muotoilua."
,
"hide_network_description"
:
"Älä näytä seurauksiani tai seuraajiani"
,
"nsfw_clickthrough"
:
"Piilota NSFW liitteet klikkauksen taakse"
,
...
...
src/modules/config.js
View file @
23d91b78
...
...
@@ -20,6 +20,7 @@ export const defaultState = {
autoLoad
:
true
,
streaming
:
true
,
hoverPreview
:
true
,
emojiReactionsOnTimeline
:
true
,
autohideFloatingPostButton
:
false
,
pauseOnUnfocused
:
true
,
stopGifs
:
false
,
...
...
@@ -29,7 +30,8 @@ export const defaultState = {
mentions
:
true
,
likes
:
true
,
repeats
:
true
,
moves
:
true
moves
:
true
,
emojiReactions
:
false
},
webPushNotifications
:
false
,
muteWords
:
[],
...
...
src/modules/statuses.js
View file @
23d91b78
...
...
@@ -81,7 +81,8 @@ const visibleNotificationTypes = (rootState) => {
rootState
.
config
.
notificationVisibility
.
mentions
&&
'
mention
'
,
rootState
.
config
.
notificationVisibility
.
repeats
&&
'
repeat
'
,
rootState
.
config
.
notificationVisibility
.
follows
&&
'
follow
'
,
rootState
.
config
.
notificationVisibility
.
moves
&&
'
move
'
rootState
.
config
.
notificationVisibility
.
moves
&&
'
move
'
,
rootState
.
config
.
notificationVisibility
.
emojiReactions
&&
'
pleroma:emoji_reactions
'
].
filter
(
_
=>
_
)
}
...
...
@@ -325,6 +326,10 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
notification
.
status
=
notification
.
status
&&
addStatusToGlobalStorage
(
state
,
notification
.
status
).
item
}
if
(
notification
.
type
===
'
pleroma:emoji_reaction
'
)
{
dispatch
(
'
fetchEmojiReactionsBy
'
,
notification
.
status
.
id
)
}
// Only add a new notification if we don't have one for the same action
if
(
!
state
.
notifications
.
idStore
.
hasOwnProperty
(
notification
.
id
))
{
state
.
notifications
.
maxId
=
notification
.
id
>
state
.
notifications
.
maxId
...
...
@@ -358,7 +363,9 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
break
}
if
(
i18nString
)
{
if
(
notification
.
type
===
'
pleroma:emoji_reaction
'
)
{
notifObj
.
body
=
rootGetters
.
i18n
.
t
(
'
notifications.reacted_with
'
,
[
notification
.
emoji
])
}
else
if
(
i18nString
)
{
notifObj
.
body
=
rootGetters
.
i18n
.
t
(
'
notifications.
'
+
i18nString
)
}
else
{
notifObj
.
body
=
notification
.
status
.
text
...
...
@@ -371,10 +378,10 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
}
if
(
!
notification
.
seen
&&
!
state
.
notifications
.
desktopNotificationSilence
&&
visibleNotificationTypes
.
includes
(
notification
.
type
))
{
let
n
otification
=
new
window
.
Notification
(
title
,
notifObj
)
let
desktopN
otification
=
new
window
.
Notification
(
title
,
notifObj
)
// Chrome is known for not closing notifications automatically
// according to MDN, anyway.
setTimeout
(
notification
.
close
.
bind
(
n
otification
),
5000
)
setTimeout
(
desktopNotification
.
close
.
bind
(
desktopN
otification
),
5000
)
}
}
}
else
if
(
notification
.
seen
)
{
...
...
@@ -537,12 +544,13 @@ export const mutations = {
},
addOwnReaction
(
state
,
{
id
,
emoji
,
currentUser
})
{
const
status
=
state
.
allStatusesObject
[
id
]
const
reactionIndex
=
findIndex
(
status
.
emoji_reactions
,
{
emoji
})
const
reaction
=
status
.
emoji_reactions
[
reactionIndex
]
||
{
emoji
,
count
:
0
,
accounts
:
[]
}
const
reactionIndex
=
findIndex
(
status
.
emoji_reactions
,
{
name
:
emoji
})
const
reaction
=
status
.
emoji_reactions
[
reactionIndex
]
||
{
name
:
emoji
,
count
:
0
,
accounts
:
[]
}
const
newReaction
=
{
...
reaction
,
count
:
reaction
.
count
+
1
,
me
:
true
,
accounts
:
[
...
reaction
.
accounts
,
currentUser
...
...
@@ -558,21 +566,23 @@ export const mutations = {
},
removeOwnReaction
(
state
,
{
id
,
emoji
,
currentUser
})
{
const
status
=
state
.
allStatusesObject
[
id
]
const
reactionIndex
=
findIndex
(
status
.
emoji_reactions
,
{
emoji
})
const
reactionIndex
=
findIndex
(
status
.
emoji_reactions
,
{
name
:
emoji
})
if
(
reactionIndex
<
0
)
return
const
reaction
=
status
.
emoji_reactions
[
reactionIndex
]
const
accounts
=
reaction
.
accounts
||
[]
const
newReaction
=
{
...
reaction
,
count
:
reaction
.
count
-
1
,
accounts
:
reaction
.
accounts
.
filter
(
acc
=>
acc
.
id
===
currentUser
.
id
)
me
:
false
,
accounts
:
accounts
.
filter
(
acc
=>
acc
.
id
!==
currentUser
.
id
)
}
if
(
newReaction
.
count
>
0
)
{
set
(
status
.
emoji_reactions
,
reactionIndex
,
newReaction
)
}
else
{
set
(
status
,
'
emoji_reactions
'
,
status
.
emoji_reactions
.
filter
(
r
=>
r
.
emoji
!==
emoji
))
set
(
status
,
'
emoji_reactions
'
,
status
.
emoji_reactions
.
filter
(
r
=>
r
.
name
!==
emoji
))
}
},
updateStatusWithPoll
(
state
,
{
id
,
poll
})
{
...
...
@@ -681,18 +691,22 @@ const statuses = {
},
reactWithEmoji
({
rootState
,
dispatch
,
commit
},
{
id
,
emoji
})
{
const
currentUser
=
rootState
.
users
.
currentUser
if
(
!
currentUser
)
return
commit
(
'
addOwnReaction
'
,
{
id
,
emoji
,
currentUser
})
rootState
.
api
.
backendInteractor
.
reactWithEmoji
({
id
,
emoji
}).
then
(
status
=>
{
ok
=>
{
dispatch
(
'
fetchEmojiReactionsBy
'
,
id
)
}
)
},
unreactWithEmoji
({
rootState
,
dispatch
,
commit
},
{
id
,
emoji
})
{
const
currentUser
=
rootState
.
users
.
currentUser
if
(
!
currentUser
)
return
commit
(
'
removeOwnReaction
'
,
{
id
,
emoji
,
currentUser
})
rootState
.
api
.
backendInteractor
.
unreactWithEmoji
({
id
,
emoji
}).
then
(
status
=>
{
ok
=>
{
dispatch
(
'
fetchEmojiReactionsBy
'
,
id
)
}
)
...
...
src/services/api/api.service.js
View file @
23d91b78
...
...
@@ -74,9 +74,9 @@ const MASTODON_SEARCH_2 = `/api/v2/search`
const
MASTODON_USER_SEARCH_URL
=
'
/api/v1/accounts/search
'
const
MASTODON_DOMAIN_BLOCKS_URL
=
'
/api/v1/domain_blocks
'
const
MASTODON_STREAMING
=
'
/api/v1/streaming
'
const
PLEROMA_EMOJI_REACTIONS_URL
=
id
=>
`/api/v1/pleroma/statuses/
${
id
}
/
emoji_reactions_by
`
const
PLEROMA_EMOJI_REACT_URL
=
id
=>
`/api/v1/pleroma/statuses/
${
id
}
/react_with_emoji
`
const
PLEROMA_EMOJI_UNREACT_URL
=
id
=>
`/api/v1/pleroma/statuses/
${
id
}
/unreact_with_emoji
`
const
PLEROMA_EMOJI_REACTIONS_URL
=
id
=>
`/api/v1/pleroma/statuses/
${
id
}
/
reactions
`
const
PLEROMA_EMOJI_REACT_URL
=
(
id
,
emoji
)
=>
`/api/v1/pleroma/statuses/
${
id
}
/reactions/
${
emoji
}
`
const
PLEROMA_EMOJI_UNREACT_URL
=
(
id
,
emoji
)
=>
`/api/v1/pleroma/statuses/
${
id
}
/reactions/
${
emoji
}
`
const
oldfetch
=
window
.
fetch
...
...
@@ -888,25 +888,27 @@ const fetchRebloggedByUsers = ({ id }) => {
return
promisedRequest
({
url
:
MASTODON_STATUS_REBLOGGEDBY_URL
(
id
)
}).
then
((
users
)
=>
users
.
map
(
parseUser
))
}
const
fetchEmojiReactions
=
({
id
})
=>
{
return
promisedRequest
({
url
:
PLEROMA_EMOJI_REACTIONS_URL
(
id
)
})
const
fetchEmojiReactions
=
({
id
,
credentials
})
=>
{
return
promisedRequest
({
url
:
PLEROMA_EMOJI_REACTIONS_URL
(
id
),
credentials
})
.
then
((
reactions
)
=>
reactions
.
map
(
r
=>
{
r
.
accounts
=
r
.
accounts
.
map
(
parseUser
)
return
r
}))
}
const
reactWithEmoji
=
({
id
,
emoji
,
credentials
})
=>
{
return
promisedRequest
({
url
:
PLEROMA_EMOJI_REACT_URL
(
id
),
method
:
'
POST
'
,
credentials
,
payload
:
{
emoji
}
url
:
PLEROMA_EMOJI_REACT_URL
(
id
,
emoji
),
method
:
'
PUT
'
,
credentials
}).
then
(
parseStatus
)
}
const
unreactWithEmoji
=
({
id
,
emoji
,
credentials
})
=>
{
return
promisedRequest
({
url
:
PLEROMA_EMOJI_UNREACT_URL
(
id
),
method
:
'
POST
'
,
credentials
,
payload
:
{
emoji
}
url
:
PLEROMA_EMOJI_UNREACT_URL
(
id
,
emoji
),
method
:
'
DELETE
'
,
credentials
}).
then
(
parseStatus
)
}
...
...
src/services/entity_normalizer/entity_normalizer.service.js
View file @
23d91b78
...
...
@@ -354,6 +354,7 @@ export const parseNotification = (data) => {
?
null
:
parseUser
(
data
.
target
)
output
.
from_profile
=
parseUser
(
data
.
account
)
output
.
emoji
=
data
.
emoji
}
else
{
const
parsedNotice
=
parseStatus
(
data
.
notice
)
output
.
type
=
data
.
ntype
...
...
src/services/notification_utils/notification_utils.js
View file @
23d91b78
...
...
@@ -7,7 +7,8 @@ export const visibleTypes = store => ([
store
.
state
.
config
.
notificationVisibility
.
mentions
&&
'
mention
'
,
store
.
state
.
config
.
notificationVisibility
.
repeats
&&
'
repeat
'
,
store
.
state
.
config
.
notificationVisibility
.
follows
&&
'
follow
'
,
store
.
state
.
config
.
notificationVisibility
.
moves
&&
'
move
'
store
.
state
.
config
.
notificationVisibility
.
moves
&&
'
move
'
,
store
.
state
.
config
.
notificationVisibility
.
emojiReactions
&&
'
pleroma:emoji_reaction
'
].
filter
(
_
=>
_
))
const
sortById
=
(
a
,
b
)
=>
{
...
...
test/unit/specs/modules/statuses.spec.js
View file @
23d91b78
...
...
@@ -245,11 +245,12 @@ describe('Statuses module', () => {
it
(
'
increments count in existing reaction
'
,
()
=>
{
const
state
=
defaultState
()
const
status
=
makeMockStatus
({
id
:
'
1
'
})
status
.
emoji_reactions
=
[
{
emoji
:
'
😂
'
,
count
:
1
,
accounts
:
[]
}
]
status
.
emoji_reactions
=
[
{
name
:
'
😂
'
,
count
:
1
,
accounts
:
[]
}
]
mutations
.
addNewStatuses
(
state
,
{
statuses
:
[
status
],
showImmediately
:
true
,
timeline
:
'
public
'
})
mutations
.
addOwnReaction
(
state
,
{
id
:
'
1
'
,
emoji
:
'
😂
'
,
currentUser
:
{
id
:
'
me
'
}
})
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
count
).
to
.
eql
(
2
)
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
me
).
to
.
eql
(
true
)
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
accounts
[
0
].
id
).
to
.
eql
(
'
me
'
)
})
...
...
@@ -261,27 +262,29 @@ describe('Statuses module', () => {
mutations
.
addNewStatuses
(
state
,
{
statuses
:
[
status
],
showImmediately
:
true
,
timeline
:
'
public
'
})
mutations
.
addOwnReaction
(
state
,
{
id
:
'
1
'
,
emoji
:
'
😂
'
,
currentUser
:
{
id
:
'
me
'
}
})
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
count
).
to
.
eql
(
1
)
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
me
).
to
.
eql
(
true
)
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
accounts
[
0
].
id
).
to
.
eql
(
'
me
'
)
})
it
(
'
decreases count in existing reaction
'
,
()
=>
{
const
state
=
defaultState
()
const
status
=
makeMockStatus
({
id
:
'
1
'
})
status
.
emoji_reactions
=
[
{
emoji
:
'
😂
'
,
count
:
2
,
accounts
:
[{
id
:
'
me
'
}]
}
]
status
.
emoji_reactions
=
[
{
name
:
'
😂
'
,
count
:
2
,
accounts
:
[{
id
:
'
me
'
}]
}
]
mutations
.
addNewStatuses
(
state
,
{
statuses
:
[
status
],
showImmediately
:
true
,
timeline
:
'
public
'
})
mutations
.
removeOwnReaction
(
state
,
{
id
:
'
1
'
,
emoji
:
'
😂
'
,
currentUser
:
{}
})
mutations
.
removeOwnReaction
(
state
,
{
id
:
'
1
'
,
emoji
:
'
😂
'
,
currentUser
:
{
id
:
'
me
'
}
})
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
count
).
to
.
eql
(
1
)
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
me
).
to
.
eql
(
false
)
expect
(
state
.
allStatusesObject
[
'
1
'
].
emoji_reactions
[
0
].
accounts
).
to
.
eql
([])
})
it
(
'
removes a reaction
'
,
()
=>
{
const
state
=
defaultState
()
const
status
=
makeMockStatus
({
id
:
'
1
'
})
status
.
emoji_reactions
=
[{
emoji
:
'
😂
'
,
count
:
1
,
accounts
:
[{
id
:
'
me
'
}]
}]
status
.
emoji_reactions
=
[{
name
:
'
😂
'
,
count
:
1
,
accounts
:
[{
id
:
'
me
'
}]
}]