Implement domain mutes v2
This commit is contained in:
parent
e3de2964cc
commit
7a013ac393
7 changed files with 265 additions and 49 deletions
15
src/components/domain_mute_card/domain_mute_card.js
Normal file
15
src/components/domain_mute_card/domain_mute_card.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import ProgressButton from '../progress_button/progress_button.vue'
|
||||
|
||||
const DomainMuteCard = {
|
||||
props: ['domain'],
|
||||
components: {
|
||||
ProgressButton
|
||||
},
|
||||
methods: {
|
||||
unmuteDomain () {
|
||||
return this.$store.dispatch('unmuteDomain', this.domain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DomainMuteCard
|
38
src/components/domain_mute_card/domain_mute_card.vue
Normal file
38
src/components/domain_mute_card/domain_mute_card.vue
Normal file
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<div class="domain-mute-card">
|
||||
<div class="domain-mute-card-domain">
|
||||
{{ domain }}
|
||||
</div>
|
||||
<ProgressButton
|
||||
:click="unmuteDomain"
|
||||
class="btn btn-default"
|
||||
>
|
||||
{{ $t('domain_mute_card.unmute') }}
|
||||
<template slot="progress">
|
||||
{{ $t('domain_mute_card.unmute_progress') }}
|
||||
</template>
|
||||
</ProgressButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./domain_mute_card.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
.domain-mute-card {
|
||||
flex: 1 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.6em 1em 0.6em 0;
|
||||
|
||||
&-domain {
|
||||
margin-right: 1em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 10em;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -9,6 +9,7 @@ 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 DomainMuteCard from '../domain_mute_card/domain_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'
|
||||
|
@ -32,6 +33,12 @@ const MuteList = withSubscription({
|
|||
childPropName: 'items'
|
||||
})(SelectableList)
|
||||
|
||||
const DomainMuteList = withSubscription({
|
||||
fetch: (props, $store) => $store.dispatch('fetchDomainMutes'),
|
||||
select: (props, $store) => get($store.state.users.currentUser, 'domainMutes', []),
|
||||
childPropName: 'items'
|
||||
})(SelectableList)
|
||||
|
||||
const UserSettings = {
|
||||
data () {
|
||||
return {
|
||||
|
@ -67,7 +74,8 @@ const UserSettings = {
|
|||
changedPassword: false,
|
||||
changePasswordError: false,
|
||||
activeTab: 'profile',
|
||||
notificationSettings: this.$store.state.users.currentUser.notification_settings
|
||||
notificationSettings: this.$store.state.users.currentUser.notification_settings,
|
||||
newDomainToMute: ''
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
@ -80,10 +88,12 @@ const UserSettings = {
|
|||
ImageCropper,
|
||||
BlockList,
|
||||
MuteList,
|
||||
DomainMuteList,
|
||||
EmojiInput,
|
||||
Autosuggest,
|
||||
BlockCard,
|
||||
MuteCard,
|
||||
DomainMuteCard,
|
||||
ProgressButton,
|
||||
Importer,
|
||||
Exporter,
|
||||
|
@ -365,6 +375,13 @@ const UserSettings = {
|
|||
unmuteUsers (ids) {
|
||||
return this.$store.dispatch('unmuteUsers', ids)
|
||||
},
|
||||
unmuteDomains (domains) {
|
||||
return this.$store.dispatch('unmuteDomains', domains)
|
||||
},
|
||||
muteDomain () {
|
||||
return this.$store.dispatch('muteDomain', this.newDomainToMute)
|
||||
.then(() => { this.newDomainToMute = '' })
|
||||
},
|
||||
identity (value) {
|
||||
return value
|
||||
}
|
||||
|
|
|
@ -509,59 +509,114 @@
|
|||
</div>
|
||||
|
||||
<div :label="$t('settings.mutes_tab')">
|
||||
<div class="profile-edit-usersearch-wrapper">
|
||||
<Autosuggest
|
||||
:filter="filterUnMutedUsers"
|
||||
:query="queryUserIds"
|
||||
:placeholder="$t('settings.search_user_to_mute')"
|
||||
>
|
||||
<MuteCard
|
||||
slot-scope="row"
|
||||
:user-id="row.item"
|
||||
/>
|
||||
</Autosuggest>
|
||||
</div>
|
||||
<MuteList
|
||||
:refresh="true"
|
||||
:get-key="identity"
|
||||
>
|
||||
<template
|
||||
slot="header"
|
||||
slot-scope="{selected}"
|
||||
>
|
||||
<div class="profile-edit-bulk-actions">
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
:click="() => muteUsers(selected)"
|
||||
<tab-switcher>
|
||||
<div label="Users">
|
||||
<div class="profile-edit-usersearch-wrapper">
|
||||
<Autosuggest
|
||||
:filter="filterUnMutedUsers"
|
||||
:query="queryUserIds"
|
||||
:placeholder="$t('settings.search_user_to_mute')"
|
||||
>
|
||||
{{ $t('user_card.mute') }}
|
||||
<template slot="progress">
|
||||
{{ $t('user_card.mute_progress') }}
|
||||
</template>
|
||||
</ProgressButton>
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
:click="() => unmuteUsers(selected)"
|
||||
<MuteCard
|
||||
slot-scope="row"
|
||||
:user-id="row.item"
|
||||
/>
|
||||
</Autosuggest>
|
||||
</div>
|
||||
<MuteList
|
||||
:refresh="true"
|
||||
:get-key="identity"
|
||||
>
|
||||
<template
|
||||
slot="header"
|
||||
slot-scope="{selected}"
|
||||
>
|
||||
{{ $t('user_card.unmute') }}
|
||||
<div class="profile-edit-bulk-actions">
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
:click="() => muteUsers(selected)"
|
||||
>
|
||||
{{ $t('user_card.mute') }}
|
||||
<template slot="progress">
|
||||
{{ $t('user_card.mute_progress') }}
|
||||
</template>
|
||||
</ProgressButton>
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
:click="() => unmuteUsers(selected)"
|
||||
>
|
||||
{{ $t('user_card.unmute') }}
|
||||
<template slot="progress">
|
||||
{{ $t('user_card.unmute_progress') }}
|
||||
</template>
|
||||
</ProgressButton>
|
||||
</div>
|
||||
</template>
|
||||
<template
|
||||
slot="item"
|
||||
slot-scope="{item}"
|
||||
>
|
||||
<MuteCard :user-id="item" />
|
||||
</template>
|
||||
<template slot="empty">
|
||||
{{ $t('settings.no_mutes') }}
|
||||
</template>
|
||||
</MuteList>
|
||||
</div>
|
||||
|
||||
<div :label="$t('settings.domain_mutes')">
|
||||
<div class="profile-edit-domain-mute-form">
|
||||
<input
|
||||
v-model="newDomainToMute"
|
||||
:placeholder="$t('settings.type_domains_to_mute')"
|
||||
type="text"
|
||||
@keyup.enter="muteDomain"
|
||||
>
|
||||
<ProgressButton
|
||||
class="btn btn-default"
|
||||
:click="muteDomain"
|
||||
>
|
||||
{{ $t('domain_mute_card.mute') }}
|
||||
<template slot="progress">
|
||||
{{ $t('user_card.unmute_progress') }}
|
||||
{{ $t('domain_mute_card.mute_progress') }}
|
||||
</template>
|
||||
</ProgressButton>
|
||||
</div>
|
||||
</template>
|
||||
<template
|
||||
slot="item"
|
||||
slot-scope="{item}"
|
||||
>
|
||||
<MuteCard :user-id="item" />
|
||||
</template>
|
||||
<template slot="empty">
|
||||
{{ $t('settings.no_mutes') }}
|
||||
</template>
|
||||
</MuteList>
|
||||
<DomainMuteList
|
||||
:refresh="true"
|
||||
:get-key="identity"
|
||||
>
|
||||
<template
|
||||
slot="header"
|
||||
slot-scope="{selected}"
|
||||
>
|
||||
<div class="profile-edit-bulk-actions">
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
:click="() => unmuteDomains(selected)"
|
||||
>
|
||||
{{ $t('domain_mute_card.unmute') }}
|
||||
<template slot="progress">
|
||||
{{ $t('domain_mute_card.unmute_progress') }}
|
||||
</template>
|
||||
</ProgressButton>
|
||||
</div>
|
||||
</template>
|
||||
<template
|
||||
slot="item"
|
||||
slot-scope="{item}"
|
||||
>
|
||||
<DomainMuteCard :domain="item" />
|
||||
</template>
|
||||
<template slot="empty">
|
||||
{{ $t('settings.no_mutes') }}
|
||||
</template>
|
||||
</DomainMuteList>
|
||||
</div>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
|
@ -639,6 +694,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
&-domain-mute-form {
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
button {
|
||||
align-self: flex-end;
|
||||
margin-top: 1em;
|
||||
width: 10em;
|
||||
}
|
||||
}
|
||||
|
||||
.setting-subitem {
|
||||
margin-left: 1.75em;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
"chat": {
|
||||
"title": "Chat"
|
||||
},
|
||||
"domain_mute_card": {
|
||||
"mute": "Mute",
|
||||
"mute_progress": "Muting...",
|
||||
"unmute": "Unmute",
|
||||
"unmute_progress": "Unmuting..."
|
||||
},
|
||||
"exporter": {
|
||||
"export": "Export",
|
||||
"processing": "Processing, you'll soon be asked to download your file"
|
||||
|
@ -264,6 +270,7 @@
|
|||
"delete_account_error": "There was an issue deleting your account. If this persists please contact your instance administrator.",
|
||||
"delete_account_instructions": "Type your password in the input below to confirm account deletion.",
|
||||
"discoverable": "Allow discovery of this account in search results and other services",
|
||||
"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",
|
||||
"export_theme": "Save preset",
|
||||
|
@ -361,6 +368,7 @@
|
|||
"post_status_content_type": "Post status content type",
|
||||
"stop_gifs": "Play-on-hover GIFs",
|
||||
"streaming": "Enable automatic streaming of new posts when scrolled to the top",
|
||||
"user_mutes": "Users",
|
||||
"useStreamingApi": "Receive posts and notifications real-time",
|
||||
"useStreamingApiWarning": "(Not recommended, experimental, known to skip posts)",
|
||||
"text": "Text",
|
||||
|
@ -369,6 +377,7 @@
|
|||
"theme_help_v2_1": "You can also override certain component's colors and opacity by toggling the checkbox, use \"Clear all\" button to clear all overrides.",
|
||||
"theme_help_v2_2": "Icons underneath some entries are background/text contrast indicators, hover over for detailed info. Please keep in mind that when using transparency contrast indicators show the worst possible case.",
|
||||
"tooltipRadius": "Tooltips/alerts",
|
||||
"type_domains_to_mute": "Type in domains to mute",
|
||||
"upload_a_photo": "Upload a photo",
|
||||
"user_settings": "User Settings",
|
||||
"values": {
|
||||
|
|
|
@ -72,6 +72,16 @@ const showReblogs = (store, userId) => {
|
|||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
}
|
||||
|
||||
const muteDomain = (store, domain) => {
|
||||
return store.rootState.api.backendInteractor.muteDomain({ domain })
|
||||
.then(() => store.commit('addDomainMute', domain))
|
||||
}
|
||||
|
||||
const unmuteDomain = (store, domain) => {
|
||||
return store.rootState.api.backendInteractor.unmuteDomain({ domain })
|
||||
.then(() => store.commit('removeDomainMute', domain))
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
setMuted (state, { user: { id }, muted }) {
|
||||
const user = state.usersObject[id]
|
||||
|
@ -177,6 +187,20 @@ export const mutations = {
|
|||
state.currentUser.muteIds.push(muteId)
|
||||
}
|
||||
},
|
||||
saveDomainMutes (state, domainMutes) {
|
||||
state.currentUser.domainMutes = domainMutes
|
||||
},
|
||||
addDomainMute (state, domain) {
|
||||
if (state.currentUser.domainMutes.indexOf(domain) === -1) {
|
||||
state.currentUser.domainMutes.push(domain)
|
||||
}
|
||||
},
|
||||
removeDomainMute (state, domain) {
|
||||
const index = state.currentUser.domainMutes.indexOf(domain)
|
||||
if (index !== -1) {
|
||||
state.currentUser.domainMutes.splice(index, 1)
|
||||
}
|
||||
},
|
||||
setPinnedToUser (state, status) {
|
||||
const user = state.usersObject[status.user.id]
|
||||
const index = user.pinnedStatusIds.indexOf(status.id)
|
||||
|
@ -297,6 +321,25 @@ const users = {
|
|||
unmuteUsers (store, ids = []) {
|
||||
return Promise.all(ids.map(id => unmuteUser(store, id)))
|
||||
},
|
||||
fetchDomainMutes (store) {
|
||||
return store.rootState.api.backendInteractor.fetchDomainMutes()
|
||||
.then((domainMutes) => {
|
||||
store.commit('saveDomainMutes', domainMutes)
|
||||
return domainMutes
|
||||
})
|
||||
},
|
||||
muteDomain (store, domain) {
|
||||
return muteDomain(store, domain)
|
||||
},
|
||||
unmuteDomain (store, domain) {
|
||||
return unmuteDomain(store, domain)
|
||||
},
|
||||
muteDomains (store, domains = []) {
|
||||
return Promise.all(domains.map(domain => muteDomain(store, domain)))
|
||||
},
|
||||
unmuteDomains (store, domain = []) {
|
||||
return Promise.all(domain.map(domain => unmuteDomain(store, domain)))
|
||||
},
|
||||
fetchFriends ({ rootState, commit }, id) {
|
||||
const user = rootState.users.usersObject[id]
|
||||
const maxId = last(user.friendIds)
|
||||
|
@ -460,6 +503,7 @@ const users = {
|
|||
user.credentials = accessToken
|
||||
user.blockIds = []
|
||||
user.muteIds = []
|
||||
user.domainMutes = []
|
||||
commit('setCurrentUser', user)
|
||||
commit('addNewUsers', [user])
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ const MASTODON_MUTE_CONVERSATION = id => `/api/v1/statuses/${id}/mute`
|
|||
const MASTODON_UNMUTE_CONVERSATION = id => `/api/v1/statuses/${id}/unmute`
|
||||
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 oldfetch = window.fetch
|
||||
|
@ -948,6 +949,28 @@ const search2 = ({ credentials, q, resolve, limit, offset, following }) => {
|
|||
})
|
||||
}
|
||||
|
||||
const fetchDomainMutes = ({ credentials }) => {
|
||||
return promisedRequest({ url: MASTODON_DOMAIN_BLOCKS_URL, credentials })
|
||||
}
|
||||
|
||||
const muteDomain = ({ domain, credentials }) => {
|
||||
return promisedRequest({
|
||||
url: MASTODON_DOMAIN_BLOCKS_URL,
|
||||
method: 'POST',
|
||||
payload: { domain },
|
||||
credentials
|
||||
})
|
||||
}
|
||||
|
||||
const unmuteDomain = ({ domain, credentials }) => {
|
||||
return promisedRequest({
|
||||
url: MASTODON_DOMAIN_BLOCKS_URL,
|
||||
method: 'DELETE',
|
||||
payload: { domain },
|
||||
credentials
|
||||
})
|
||||
}
|
||||
|
||||
export const getMastodonSocketURI = ({ credentials, stream, args = {} }) => {
|
||||
return Object.entries({
|
||||
...(credentials
|
||||
|
@ -1110,7 +1133,10 @@ const apiService = {
|
|||
reportUser,
|
||||
updateNotificationSettings,
|
||||
search2,
|
||||
searchUsers
|
||||
searchUsers,
|
||||
fetchDomainMutes,
|
||||
muteDomain,
|
||||
unmuteDomain
|
||||
}
|
||||
|
||||
export default apiService
|
||||
|
|
Loading…
Reference in a new issue