Merge remote-tracking branch 'origin/develop' into shigusegubu-vue3
* origin/develop: (22 commits) Fix lint stuff Lists implementation: make route naming consistent Lists implementation: tests, linter fix Lists implementation Update babel monorepo to v7.18.10 clean up leftover Use empty array for emji instead Add default array for RichContent emoji Use RichContent component for Reports Use Select component Make linter happy Fix up and code review Fix setting report state, add proper error handling remove logs Fix report modal not working, add include_types remove mock data add proper state switcher wip separated component somewhat workign version still with fixture ...
This commit is contained in:
commit
fa4c827df6
50 changed files with 1659 additions and 135 deletions
|
@ -46,9 +46,9 @@
|
|||
"vuex": "4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.18.9",
|
||||
"@babel/plugin-transform-runtime": "7.18.9",
|
||||
"@babel/preset-env": "7.18.9",
|
||||
"@babel/core": "7.18.10",
|
||||
"@babel/plugin-transform-runtime": "7.18.10",
|
||||
"@babel/preset-env": "7.18.10",
|
||||
"@babel/register": "7.18.9",
|
||||
"@babel/eslint-parser": "7.18.9",
|
||||
"@intlify/vue-i18n-loader": "^5.0.0",
|
||||
|
|
|
@ -20,6 +20,9 @@ import ShoutPanel from 'components/shout_panel/shout_panel.vue'
|
|||
import WhoToFollow from 'components/who_to_follow/who_to_follow.vue'
|
||||
import About from 'components/about/about.vue'
|
||||
import RemoteUserResolver from 'components/remote_user_resolver/remote_user_resolver.vue'
|
||||
import Lists from 'components/lists/lists.vue'
|
||||
import ListsTimeline from 'components/lists_timeline/lists_timeline.vue'
|
||||
import ListsEdit from 'components/lists_edit/lists_edit.vue'
|
||||
|
||||
export default (store) => {
|
||||
const validateAuthenticatedRoute = (to, from, next) => {
|
||||
|
@ -72,7 +75,10 @@ export default (store) => {
|
|||
{ name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
|
||||
{ name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute },
|
||||
{ name: 'about', path: '/about', component: About },
|
||||
{ name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile }
|
||||
{ name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile },
|
||||
{ name: 'lists', path: '/lists', component: Lists },
|
||||
{ name: 'lists-timeline', path: '/lists/:id', component: ListsTimeline },
|
||||
{ name: 'lists-edit', path: '/lists/:id/edit', component: ListsEdit }
|
||||
]
|
||||
|
||||
if (store.state.instance.pleromaChatMessagesAvailable) {
|
||||
|
|
|
@ -5,6 +5,8 @@ const tabModeDict = {
|
|||
mentions: ['mention'],
|
||||
'likes+repeats': ['repeat', 'like'],
|
||||
follows: ['follow'],
|
||||
reactions: ['pleroma:emoji_reaction'],
|
||||
reports: ['pleroma:report'],
|
||||
moves: ['move']
|
||||
}
|
||||
|
||||
|
@ -12,7 +14,8 @@ const Interactions = {
|
|||
data () {
|
||||
return {
|
||||
allowFollowingMove: this.$store.state.users.currentUser.allow_following_move,
|
||||
filterMode: tabModeDict.mentions
|
||||
filterMode: tabModeDict.mentions,
|
||||
canSeeReports: ['moderator', 'admin'].includes(this.$store.state.users.currentUser.role)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -21,6 +21,15 @@
|
|||
key="follows"
|
||||
:label="$t('interactions.follows')"
|
||||
/>
|
||||
<span
|
||||
key="reactions"
|
||||
:label="$t('interactions.emoji_reactions')"
|
||||
/>
|
||||
<span
|
||||
v-if="canSeeReports"
|
||||
key="reports"
|
||||
:label="$t('interactions.reports')"
|
||||
/>
|
||||
<span
|
||||
v-if="!allowFollowingMove"
|
||||
key="moves"
|
||||
|
|
32
src/components/lists/lists.js
Normal file
32
src/components/lists/lists.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
import ListsCard from '../lists_card/lists_card.vue'
|
||||
import ListsNew from '../lists_new/lists_new.vue'
|
||||
|
||||
const Lists = {
|
||||
data () {
|
||||
return {
|
||||
isNew: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ListsCard,
|
||||
ListsNew
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('startFetchingLists')
|
||||
},
|
||||
computed: {
|
||||
lists () {
|
||||
return this.$store.state.lists.allLists
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancelNewList () {
|
||||
this.isNew = false
|
||||
},
|
||||
newList () {
|
||||
this.isNew = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Lists
|
31
src/components/lists/lists.vue
Normal file
31
src/components/lists/lists.vue
Normal file
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<div v-if="isNew">
|
||||
<ListsNew @cancel="cancelNewList" />
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="settings panel panel-default"
|
||||
>
|
||||
<div class="panel-heading">
|
||||
<div class="title">
|
||||
{{ $t('lists.lists') }}
|
||||
</div>
|
||||
<button
|
||||
class="button-default"
|
||||
@click="newList"
|
||||
>
|
||||
{{ $t("lists.new") }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ListsCard
|
||||
v-for="list in lists.slice().reverse()"
|
||||
:key="list"
|
||||
:list="list"
|
||||
class="list-item"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./lists.js"></script>
|
16
src/components/lists_card/lists_card.js
Normal file
16
src/components/lists_card/lists_card.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faEllipsisH
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faEllipsisH
|
||||
)
|
||||
|
||||
const ListsCard = {
|
||||
props: [
|
||||
'list'
|
||||
]
|
||||
}
|
||||
|
||||
export default ListsCard
|
51
src/components/lists_card/lists_card.vue
Normal file
51
src/components/lists_card/lists_card.vue
Normal file
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div class="list-card">
|
||||
<router-link
|
||||
:to="{ name: 'lists-timeline', params: { id: list.id } }"
|
||||
class="list-name"
|
||||
>
|
||||
{{ list.title }}
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="{ name: 'lists-edit', params: { id: list.id } }"
|
||||
class="button-list-edit"
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="ellipsis-h"
|
||||
/>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./lists_card.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.list-card {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.list-name,
|
||||
.button-list-edit {
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
color: $fallback--link;
|
||||
color: var(--link, $fallback--link);
|
||||
|
||||
&:hover {
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--selectedMenu, $fallback--lightBg);
|
||||
color: $fallback--link;
|
||||
color: var(--selectedMenuText, $fallback--link);
|
||||
--faint: var(--selectedMenuFaintText, $fallback--faint);
|
||||
--faintLink: var(--selectedMenuFaintLink, $fallback--faint);
|
||||
--lightText: var(--selectedMenuLightText, $fallback--lightText);
|
||||
}
|
||||
}
|
||||
|
||||
.list-name {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
91
src/components/lists_edit/lists_edit.js
Normal file
91
src/components/lists_edit/lists_edit.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
import { mapState, mapGetters } from 'vuex'
|
||||
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
||||
import ListsUserSearch from '../lists_user_search/lists_user_search.vue'
|
||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faSearch,
|
||||
faChevronLeft
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faSearch,
|
||||
faChevronLeft
|
||||
)
|
||||
|
||||
const ListsNew = {
|
||||
components: {
|
||||
BasicUserCard,
|
||||
UserAvatar,
|
||||
ListsUserSearch
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
title: '',
|
||||
userIds: [],
|
||||
selectedUserIds: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('fetchList', { id: this.id })
|
||||
.then(() => { this.title = this.findListTitle(this.id) })
|
||||
this.$store.dispatch('fetchListAccounts', { id: this.id })
|
||||
.then(() => {
|
||||
this.selectedUserIds = this.findListAccounts(this.id)
|
||||
this.selectedUserIds.forEach(userId => {
|
||||
this.$store.dispatch('fetchUserIfMissing', userId)
|
||||
})
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
id () {
|
||||
return this.$route.params.id
|
||||
},
|
||||
users () {
|
||||
return this.userIds.map(userId => this.findUser(userId))
|
||||
},
|
||||
selectedUsers () {
|
||||
return this.selectedUserIds.map(userId => this.findUser(userId)).filter(user => user)
|
||||
},
|
||||
...mapState({
|
||||
currentUser: state => state.users.currentUser
|
||||
}),
|
||||
...mapGetters(['findUser', 'findListTitle', 'findListAccounts'])
|
||||
},
|
||||
methods: {
|
||||
onInput () {
|
||||
this.search(this.query)
|
||||
},
|
||||
selectUser (user) {
|
||||
if (this.selectedUserIds.includes(user.id)) {
|
||||
this.removeUser(user.id)
|
||||
} else {
|
||||
this.addUser(user)
|
||||
}
|
||||
},
|
||||
isSelected (user) {
|
||||
return this.selectedUserIds.includes(user.id)
|
||||
},
|
||||
addUser (user) {
|
||||
this.selectedUserIds.push(user.id)
|
||||
},
|
||||
removeUser (userId) {
|
||||
this.selectedUserIds = this.selectedUserIds.filter(id => id !== userId)
|
||||
},
|
||||
onResults (results) {
|
||||
this.userIds = results
|
||||
},
|
||||
updateList () {
|
||||
this.$store.dispatch('setList', { id: this.id, title: this.title })
|
||||
this.$store.dispatch('setListAccounts', { id: this.id, accountIds: this.selectedUserIds })
|
||||
|
||||
this.$router.push({ name: 'lists-timeline', params: { id: this.id } })
|
||||
},
|
||||
deleteList () {
|
||||
this.$store.dispatch('deleteList', { id: this.id })
|
||||
this.$router.push({ name: 'lists' })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ListsNew
|
108
src/components/lists_edit/lists_edit.vue
Normal file
108
src/components/lists_edit/lists_edit.vue
Normal file
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<div class="panel-default panel list-edit">
|
||||
<div
|
||||
ref="header"
|
||||
class="panel-heading"
|
||||
>
|
||||
<button
|
||||
class="button-unstyled go-back-button"
|
||||
@click="$router.back"
|
||||
>
|
||||
<FAIcon
|
||||
size="lg"
|
||||
icon="chevron-left"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
ref="title"
|
||||
v-model="title"
|
||||
:placeholder="$t('lists.title')"
|
||||
>
|
||||
</div>
|
||||
<div class="member-list">
|
||||
<div
|
||||
v-for="user in selectedUsers"
|
||||
:key="user.id"
|
||||
class="member"
|
||||
>
|
||||
<BasicUserCard
|
||||
:user="user"
|
||||
:class="isSelected(user) ? 'selected' : ''"
|
||||
@click.capture.prevent="selectUser(user)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ListsUserSearch @results="onResults" />
|
||||
<div class="member-list">
|
||||
<div
|
||||
v-for="user in users"
|
||||
:key="user.id"
|
||||
class="member"
|
||||
>
|
||||
<BasicUserCard
|
||||
:user="user"
|
||||
:class="isSelected(user) ? 'selected' : ''"
|
||||
@click.capture.prevent="selectUser(user)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
:disabled="title && title.length === 0"
|
||||
class="btn button-default"
|
||||
@click="updateList"
|
||||
>
|
||||
{{ $t('lists.save') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="deleteList"
|
||||
>
|
||||
{{ $t('lists.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./lists_edit.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.list-edit {
|
||||
.input-wrap {
|
||||
display: flex;
|
||||
margin: 0.7em 0.5em 0.7em 0.5em;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
|
||||
.member-list {
|
||||
padding-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
.basic-user-card:hover,
|
||||
.basic-user-card.selected {
|
||||
cursor: pointer;
|
||||
background-color: var(--selectedPost, $fallback--lightBg);
|
||||
}
|
||||
|
||||
.go-back-button {
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
height: 100%;
|
||||
align-self: start;
|
||||
width: var(--__panel-heading-height-inner);
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 0.5em;
|
||||
}
|
||||
}
|
||||
</style>
|
33
src/components/lists_menu/lists_menu_content.js
Normal file
33
src/components/lists_menu/lists_menu_content.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { mapState } from 'vuex'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faUsers,
|
||||
faGlobe,
|
||||
faBookmark,
|
||||
faEnvelope,
|
||||
faHome
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faUsers,
|
||||
faGlobe,
|
||||
faBookmark,
|
||||
faEnvelope,
|
||||
faHome
|
||||
)
|
||||
|
||||
const ListsMenuContent = {
|
||||
created () {
|
||||
this.$store.dispatch('startFetchingLists')
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
lists: state => state.lists.allLists,
|
||||
currentUser: state => state.users.currentUser,
|
||||
privateMode: state => state.instance.private,
|
||||
federating: state => state.instance.federating
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default ListsMenuContent
|
17
src/components/lists_menu/lists_menu_content.vue
Normal file
17
src/components/lists_menu/lists_menu_content.vue
Normal file
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<ul>
|
||||
<li
|
||||
v-for="list in lists.slice().reverse()"
|
||||
:key="list.id"
|
||||
>
|
||||
<router-link
|
||||
class="menu-item"
|
||||
:to="{ name: 'lists-timeline', params: { id: list.id } }"
|
||||
>
|
||||
{{ list.title }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script src="./lists_menu_content.js"></script>
|
79
src/components/lists_new/lists_new.js
Normal file
79
src/components/lists_new/lists_new.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { mapState, mapGetters } from 'vuex'
|
||||
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
|
||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import ListsUserSearch from '../lists_user_search/lists_user_search.vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faSearch,
|
||||
faChevronLeft
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faSearch,
|
||||
faChevronLeft
|
||||
)
|
||||
|
||||
const ListsNew = {
|
||||
components: {
|
||||
BasicUserCard,
|
||||
UserAvatar,
|
||||
ListsUserSearch
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
title: '',
|
||||
userIds: [],
|
||||
selectedUserIds: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
users () {
|
||||
return this.userIds.map(userId => this.findUser(userId))
|
||||
},
|
||||
selectedUsers () {
|
||||
return this.selectedUserIds.map(userId => this.findUser(userId))
|
||||
},
|
||||
...mapState({
|
||||
currentUser: state => state.users.currentUser
|
||||
}),
|
||||
...mapGetters(['findUser'])
|
||||
},
|
||||
methods: {
|
||||
goBack () {
|
||||
this.$emit('cancel')
|
||||
},
|
||||
onInput () {
|
||||
this.search(this.query)
|
||||
},
|
||||
selectUser (user) {
|
||||
if (this.selectedUserIds.includes(user.id)) {
|
||||
this.removeUser(user.id)
|
||||
} else {
|
||||
this.addUser(user)
|
||||
}
|
||||
},
|
||||
isSelected (user) {
|
||||
return this.selectedUserIds.includes(user.id)
|
||||
},
|
||||
addUser (user) {
|
||||
this.selectedUserIds.push(user.id)
|
||||
},
|
||||
removeUser (userId) {
|
||||
this.selectedUserIds = this.selectedUserIds.filter(id => id !== userId)
|
||||
},
|
||||
onResults (results) {
|
||||
this.userIds = results
|
||||
},
|
||||
createList () {
|
||||
// the API has two different endpoints for "creating a list with a name"
|
||||
// and "updating the accounts on the list".
|
||||
this.$store.dispatch('createList', { title: this.title })
|
||||
.then((list) => {
|
||||
this.$store.dispatch('setListAccounts', { id: list.id, accountIds: this.selectedUserIds })
|
||||
this.$router.push({ name: 'lists-timeline', params: { id: list.id } })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ListsNew
|
95
src/components/lists_new/lists_new.vue
Normal file
95
src/components/lists_new/lists_new.vue
Normal file
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div class="panel-default panel list-new">
|
||||
<div
|
||||
ref="header"
|
||||
class="panel-heading"
|
||||
>
|
||||
<button
|
||||
class="button-unstyled go-back-button"
|
||||
@click="goBack"
|
||||
>
|
||||
<FAIcon
|
||||
size="lg"
|
||||
icon="chevron-left"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
ref="title"
|
||||
v-model="title"
|
||||
:placeholder="$t('lists.title')"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="member-list">
|
||||
<div
|
||||
v-for="user in selectedUsers"
|
||||
:key="user.id"
|
||||
class="member"
|
||||
>
|
||||
<BasicUserCard
|
||||
:user="user"
|
||||
:class="isSelected(user) ? 'selected' : ''"
|
||||
@click.capture.prevent="selectUser(user)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ListsUserSearch
|
||||
@results="onResults"
|
||||
/>
|
||||
<div
|
||||
v-for="user in users"
|
||||
:key="user.id"
|
||||
class="member"
|
||||
>
|
||||
<BasicUserCard
|
||||
:user="user"
|
||||
:class="isSelected(user) ? 'selected' : ''"
|
||||
@click.capture.prevent="selectUser(user)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
:disabled="title && title.length === 0"
|
||||
class="btn button-default"
|
||||
@click="createList"
|
||||
>
|
||||
{{ $t('lists.create') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./lists_new.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.list-new {
|
||||
.search-icon {
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
|
||||
.member-list {
|
||||
padding-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
.basic-user-card:hover,
|
||||
.basic-user-card.selected {
|
||||
cursor: pointer;
|
||||
background-color: var(--selectedPost, $fallback--lightBg);
|
||||
}
|
||||
|
||||
.go-back-button {
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
height: 100%;
|
||||
align-self: start;
|
||||
width: var(--__panel-heading-height-inner);
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 0.5em;
|
||||
}
|
||||
}
|
||||
</style>
|
36
src/components/lists_timeline/lists_timeline.js
Normal file
36
src/components/lists_timeline/lists_timeline.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import Timeline from '../timeline/timeline.vue'
|
||||
const ListsTimeline = {
|
||||
data () {
|
||||
return {
|
||||
listId: null
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Timeline
|
||||
},
|
||||
computed: {
|
||||
timeline () { return this.$store.state.statuses.timelines.list }
|
||||
},
|
||||
watch: {
|
||||
$route: function (route) {
|
||||
if (route.name === 'lists-timeline' && route.params.id !== this.listId) {
|
||||
this.listId = route.params.id
|
||||
this.$store.dispatch('stopFetchingTimeline', 'list')
|
||||
this.$store.commit('clearTimeline', { timeline: 'list' })
|
||||
this.$store.dispatch('fetchList', { id: this.listId })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'list', listId: this.listId })
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.listId = this.$route.params.id
|
||||
this.$store.dispatch('fetchList', { id: this.listId })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'list', listId: this.listId })
|
||||
},
|
||||
unmounted () {
|
||||
this.$store.dispatch('stopFetchingTimeline', 'list')
|
||||
this.$store.commit('clearTimeline', { timeline: 'list' })
|
||||
}
|
||||
}
|
||||
|
||||
export default ListsTimeline
|
10
src/components/lists_timeline/lists_timeline.vue
Normal file
10
src/components/lists_timeline/lists_timeline.vue
Normal file
|
@ -0,0 +1,10 @@
|
|||
<template>
|
||||
<Timeline
|
||||
title="list.name"
|
||||
:timeline="timeline"
|
||||
:list-id="listId"
|
||||
timeline-name="list"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script src="./lists_timeline.js"></script>
|
46
src/components/lists_user_search/lists_user_search.js
Normal file
46
src/components/lists_user_search/lists_user_search.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faSearch,
|
||||
faChevronLeft
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { debounce } from 'lodash'
|
||||
import Checkbox from '../checkbox/checkbox.vue'
|
||||
|
||||
library.add(
|
||||
faSearch,
|
||||
faChevronLeft
|
||||
)
|
||||
|
||||
const ListsUserSearch = {
|
||||
components: {
|
||||
Checkbox
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
query: '',
|
||||
followingOnly: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onInput: debounce(function () {
|
||||
this.search(this.query)
|
||||
}, 2000),
|
||||
search (query) {
|
||||
if (!query) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
this.userIds = []
|
||||
this.$store.dispatch('search', { q: query, resolve: true, type: 'accounts', following: this.followingOnly })
|
||||
.then(data => {
|
||||
this.loading = false
|
||||
this.$emit('results', data.accounts.map(a => a.id))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ListsUserSearch
|
45
src/components/lists_user_search/lists_user_search.vue
Normal file
45
src/components/lists_user_search/lists_user_search.vue
Normal file
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="input-wrap">
|
||||
<div class="input-search">
|
||||
<FAIcon
|
||||
class="search-icon fa-scale-110 fa-old-padding"
|
||||
icon="search"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
ref="search"
|
||||
v-model="query"
|
||||
:placeholder="$t('lists.search')"
|
||||
@input="onInput"
|
||||
>
|
||||
</div>
|
||||
<div class="input-wrap">
|
||||
<Checkbox
|
||||
v-model="followingOnly"
|
||||
@change="onInput"
|
||||
>
|
||||
{{ $t('lists.following_only') }}
|
||||
</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./lists_user_search.js"></script>
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.input-wrap {
|
||||
display: flex;
|
||||
margin: 0.7em 0.5em 0.7em 0.5em;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,4 +1,5 @@
|
|||
import TimelineMenuContent from '../timeline_menu/timeline_menu_content.vue'
|
||||
import ListsMenuContent from '../lists_menu/lists_menu_content.vue'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
|
@ -12,7 +13,8 @@ import {
|
|||
faComments,
|
||||
faBell,
|
||||
faInfoCircle,
|
||||
faStream
|
||||
faStream,
|
||||
faList
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
|
@ -25,7 +27,8 @@ library.add(
|
|||
faComments,
|
||||
faBell,
|
||||
faInfoCircle,
|
||||
faStream
|
||||
faStream,
|
||||
faList
|
||||
)
|
||||
|
||||
const NavPanel = {
|
||||
|
@ -35,19 +38,27 @@ const NavPanel = {
|
|||
}
|
||||
},
|
||||
components: {
|
||||
TimelineMenuContent
|
||||
TimelineMenuContent,
|
||||
ListsMenuContent
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showTimelines: false
|
||||
showTimelines: false,
|
||||
showLists: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleTimelines () {
|
||||
this.showTimelines = !this.showTimelines
|
||||
},
|
||||
toggleLists () {
|
||||
this.showLists = !this.showLists
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
listsNavigation () {
|
||||
return this.$store.getters.mergedConfig.listsNavigation
|
||||
},
|
||||
...mapState({
|
||||
currentUser: state => state.users.currentUser,
|
||||
followRequestCount: state => state.api.followRequests.length,
|
||||
|
|
|
@ -25,6 +25,51 @@
|
|||
<TimelineMenuContent class="timelines" />
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="currentUser && listsNavigation">
|
||||
<button
|
||||
class="button-unstyled menu-item"
|
||||
@click="toggleLists"
|
||||
>
|
||||
<router-link
|
||||
:to="{ name: 'lists' }"
|
||||
@click.stop
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110"
|
||||
icon="list"
|
||||
/>{{ $t("nav.lists") }}
|
||||
</router-link>
|
||||
<FAIcon
|
||||
class="timelines-chevron"
|
||||
fixed-width
|
||||
:icon="showLists ? 'chevron-up' : 'chevron-down'"
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
v-show="showLists"
|
||||
class="timelines-background"
|
||||
>
|
||||
<ListsMenuContent class="timelines" />
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="currentUser && !listsNavigation">
|
||||
<router-link
|
||||
:to="{ name: 'lists' }"
|
||||
@click.stop
|
||||
>
|
||||
<button
|
||||
class="button-unstyled menu-item"
|
||||
@click="toggleLists"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110"
|
||||
icon="list"
|
||||
/>{{ $t("nav.lists") }}
|
||||
</button>
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser">
|
||||
<router-link
|
||||
class="menu-item"
|
||||
|
|
|
@ -4,6 +4,7 @@ import Status from '../status/status.vue'
|
|||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import UserCard from '../user_card/user_card.vue'
|
||||
import Timeago from '../timeago/timeago.vue'
|
||||
import Report from '../report/report.vue'
|
||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||
import UserPopover from '../user_popover/user_popover.vue'
|
||||
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
|
||||
|
@ -47,6 +48,7 @@ const Notification = {
|
|||
UserCard,
|
||||
Timeago,
|
||||
Status,
|
||||
Report,
|
||||
RichContent,
|
||||
UserPopover
|
||||
},
|
||||
|
|
|
@ -121,6 +121,9 @@
|
|||
</i18n-t>
|
||||
</small>
|
||||
</span>
|
||||
<span v-if="notification.type === 'pleroma:report'">
|
||||
<small>{{ $t('notifications.submitted_report') }}</small>
|
||||
</span>
|
||||
<span v-if="notification.type === 'poll'">
|
||||
<FAIcon
|
||||
class="type-icon"
|
||||
|
@ -211,6 +214,10 @@
|
|||
@{{ notification.target.screen_name_ui }}
|
||||
</router-link>
|
||||
</div>
|
||||
<Report
|
||||
v-else-if="notification.type === 'pleroma:report'"
|
||||
:report-id="notification.report.id"
|
||||
/>
|
||||
<template v-else>
|
||||
<StatusContent
|
||||
class="faint"
|
||||
|
|
|
@ -59,8 +59,10 @@
|
|||
height: 32px;
|
||||
}
|
||||
|
||||
--link: var(--faintLink);
|
||||
--text: var(--faint);
|
||||
.faint {
|
||||
--link: var(--faintLink);
|
||||
--text: var(--faint);
|
||||
}
|
||||
}
|
||||
|
||||
.follow-request-accept {
|
||||
|
|
34
src/components/report/report.js
Normal file
34
src/components/report/report.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
import Select from '../select/select.vue'
|
||||
import StatusContent from '../status_content/status_content.vue'
|
||||
import Timeago from '../timeago/timeago.vue'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
||||
const Report = {
|
||||
props: [
|
||||
'reportId'
|
||||
],
|
||||
components: {
|
||||
Select,
|
||||
StatusContent,
|
||||
Timeago
|
||||
},
|
||||
computed: {
|
||||
report () {
|
||||
return this.$store.state.reports.reports[this.reportId] || {}
|
||||
},
|
||||
state: {
|
||||
get: function () { return this.report.state },
|
||||
set: function (val) { this.setReportState(val) }
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
generateUserProfileLink (user) {
|
||||
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
|
||||
},
|
||||
setReportState (state) {
|
||||
return this.$store.dispatch('setReportState', { id: this.report.id, state })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Report
|
43
src/components/report/report.scss
Normal file
43
src/components/report/report.scss
Normal file
|
@ -0,0 +1,43 @@
|
|||
@import '../../_variables.scss';
|
||||
|
||||
.Report {
|
||||
.report-content {
|
||||
margin: 0.5em 0 1em;
|
||||
}
|
||||
|
||||
.report-state {
|
||||
margin: 0.5em 0 1em;
|
||||
}
|
||||
|
||||
.reported-status {
|
||||
border: 1px solid $fallback--faint;
|
||||
border-color: var(--faint, $fallback--faint);
|
||||
border-radius: $fallback--inputRadius;
|
||||
border-radius: var(--inputRadius, $fallback--inputRadius);
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
display: block;
|
||||
padding: 0.5em;
|
||||
margin: 0.5em 0;
|
||||
|
||||
.status-content {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.reported-status-heading {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
.reported-status-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.note {
|
||||
width: 100%;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
}
|
74
src/components/report/report.vue
Normal file
74
src/components/report/report.vue
Normal file
|
@ -0,0 +1,74 @@
|
|||
<template>
|
||||
<div class="Report">
|
||||
<div class="reported-user">
|
||||
<span>{{ $t('report.reported_user') }}</span>
|
||||
<router-link :to="generateUserProfileLink(report.acct)">
|
||||
@{{ report.acct.screen_name }}
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="reporter">
|
||||
<span>{{ $t('report.reporter') }}</span>
|
||||
<router-link :to="generateUserProfileLink(report.actor)">
|
||||
@{{ report.actor.screen_name }}
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="report-state">
|
||||
<span>{{ $t('report.state') }}</span>
|
||||
<Select
|
||||
:id="report-state"
|
||||
v-model="state"
|
||||
class="form-control"
|
||||
>
|
||||
<option
|
||||
v-for="state in ['open', 'closed', 'resolved']"
|
||||
:key="state"
|
||||
:value="state"
|
||||
>
|
||||
{{ $t('report.state_' + state) }}
|
||||
</option>
|
||||
</Select>
|
||||
</div>
|
||||
<RichContent
|
||||
class="report-content"
|
||||
:html="report.content"
|
||||
:emoji="[]"
|
||||
/>
|
||||
<div v-if="report.statuses.length">
|
||||
<small>{{ $t('report.reported_statuses') }}</small>
|
||||
<router-link
|
||||
v-for="status in report.statuses"
|
||||
:key="status.id"
|
||||
:to="{ name: 'conversation', params: { id: status.id } }"
|
||||
class="reported-status"
|
||||
>
|
||||
<div class="reported-status-heading">
|
||||
<span class="reported-status-name">{{ status.user.name }}</span>
|
||||
<Timeago
|
||||
:time="status.created_at"
|
||||
:auto-update="240"
|
||||
class="faint"
|
||||
/>
|
||||
</div>
|
||||
<status-content :status="status" />
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="report.notes.length">
|
||||
<small>{{ $t('report.notes') }}</small>
|
||||
<div
|
||||
v-for="note in report.notes"
|
||||
:key="note.id"
|
||||
class="note"
|
||||
>
|
||||
<span>{{ note.content }}</span>
|
||||
<Timeago
|
||||
:time="note.created_at"
|
||||
:auto-update="240"
|
||||
class="faint"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./report.js"></script>
|
||||
<style src="./report.scss" lang="scss"></style>
|
|
@ -124,6 +124,53 @@
|
|||
{{ $t('settings.hide_shoutbox') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path="listsNavigation">
|
||||
{{ $t('settings.lists_navigation') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<h3>{{ $t('settings.columns') }}</h3>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path="disableStickyHeaders">
|
||||
{{ $t('settings.disable_sticky_headers') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path="showScrollbars">
|
||||
{{ $t('settings.show_scrollbars') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path="sidebarRight">
|
||||
{{ $t('settings.right_sidebar') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<ChoiceSetting
|
||||
v-if="user"
|
||||
id="thirdColumnMode"
|
||||
path="thirdColumnMode"
|
||||
:options="thirdColumnModeOptions"
|
||||
>
|
||||
{{ $t('settings.third_column_mode') }}
|
||||
</ChoiceSetting>
|
||||
</li>
|
||||
<li v-if="expertLevel > 0">
|
||||
{{ $t('settings.column_sizes') }}
|
||||
<div class="column-settings">
|
||||
<SizeSetting
|
||||
v-for="column in columns"
|
||||
:key="column"
|
||||
:path="column + 'ColumnWidth'"
|
||||
:units="horizontalUnits"
|
||||
expert="1"
|
||||
>
|
||||
{{ $t('settings.column_sizes_' + column) }}
|
||||
</SizeSetting>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
|
|
|
@ -14,7 +14,8 @@ import {
|
|||
faSearch,
|
||||
faTachometerAlt,
|
||||
faCog,
|
||||
faInfoCircle
|
||||
faInfoCircle,
|
||||
faList
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
|
@ -28,7 +29,8 @@ library.add(
|
|||
faSearch,
|
||||
faTachometerAlt,
|
||||
faCog,
|
||||
faInfoCircle
|
||||
faInfoCircle,
|
||||
faList
|
||||
)
|
||||
|
||||
const SideDrawer = {
|
||||
|
|
|
@ -55,6 +55,18 @@
|
|||
/> {{ $t("nav.timelines") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li
|
||||
v-if="currentUser"
|
||||
@click="toggleDrawer"
|
||||
>
|
||||
<router-link :to="{ name: 'lists' }">
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="list"
|
||||
/> {{ $t("nav.lists") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li
|
||||
v-if="currentUser && pleromaChatMessagesAvailable"
|
||||
@click="toggleDrawer"
|
||||
|
|
|
@ -19,6 +19,7 @@ const Timeline = {
|
|||
'timelineName',
|
||||
'title',
|
||||
'userId',
|
||||
'listId',
|
||||
'tag',
|
||||
'embedded',
|
||||
'count',
|
||||
|
@ -103,6 +104,7 @@ const Timeline = {
|
|||
timeline: this.timelineName,
|
||||
showImmediately,
|
||||
userId: this.userId,
|
||||
listId: this.listId,
|
||||
tag: this.tag
|
||||
})
|
||||
},
|
||||
|
@ -158,6 +160,7 @@ const Timeline = {
|
|||
older: true,
|
||||
showImmediately: true,
|
||||
userId: this.userId,
|
||||
listId: this.listId,
|
||||
tag: this.tag
|
||||
}).then(({ statuses }) => {
|
||||
if (statuses && statuses.length === 0) {
|
||||
|
|
|
@ -58,6 +58,9 @@ const TimelineMenu = {
|
|||
if (route === 'tag-timeline') {
|
||||
return '#' + this.$route.params.tag
|
||||
}
|
||||
if (route === 'lists-timeline') {
|
||||
return this.$store.getters.findListTitle(this.$route.params.id)
|
||||
}
|
||||
const i18nkey = timelineNames()[this.$route.name]
|
||||
return i18nkey ? this.$t(i18nkey) : route
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import Status from '../status/status.vue'
|
||||
import List from '../list/list.vue'
|
||||
import Checkbox from '../checkbox/checkbox.vue'
|
||||
|
@ -21,14 +20,17 @@ const UserReportingModal = {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
reportModal () {
|
||||
return this.$store.state.reports.reportModal
|
||||
},
|
||||
isLoggedIn () {
|
||||
return !!this.$store.state.users.currentUser
|
||||
},
|
||||
isOpen () {
|
||||
return this.isLoggedIn && this.$store.state.reports.modalActivated
|
||||
return this.isLoggedIn && this.reportModal.activated
|
||||
},
|
||||
userId () {
|
||||
return this.$store.state.reports.userId
|
||||
return this.reportModal.userId
|
||||
},
|
||||
user () {
|
||||
return this.$store.getters.findUser(this.userId)
|
||||
|
@ -37,10 +39,10 @@ const UserReportingModal = {
|
|||
return !this.user.is_local && this.user.screen_name.substr(this.user.screen_name.indexOf('@') + 1)
|
||||
},
|
||||
statuses () {
|
||||
return this.$store.state.reports.statuses
|
||||
return this.reportModal.statuses
|
||||
},
|
||||
preTickedIds () {
|
||||
return this.$store.state.reports.preTickedIds
|
||||
return this.reportModal.preTickedIds
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
"more": "More",
|
||||
"loading": "Loading…",
|
||||
"generic_error": "An error occured",
|
||||
"generic_error_message": "An error occured: {0}",
|
||||
"error_retry": "Please try again",
|
||||
"retry": "Try again",
|
||||
"optional": "optional",
|
||||
|
@ -147,7 +148,8 @@
|
|||
"who_to_follow": "Who to follow",
|
||||
"preferences": "Preferences",
|
||||
"timelines": "Timelines",
|
||||
"chats": "Chats"
|
||||
"chats": "Chats",
|
||||
"lists": "Lists"
|
||||
},
|
||||
"notifications": {
|
||||
"broken_favorite": "Unknown status, searching for it…",
|
||||
|
@ -162,6 +164,7 @@
|
|||
"no_more_notifications": "No more notifications",
|
||||
"migrated_to": "migrated to",
|
||||
"reacted_with": "reacted with {0}",
|
||||
"submitted_report": "submitted a report",
|
||||
"poll_ended": "poll has ended"
|
||||
},
|
||||
"polls": {
|
||||
|
@ -197,6 +200,8 @@
|
|||
"interactions": {
|
||||
"favs_repeats": "Repeats and favorites",
|
||||
"follows": "New follows",
|
||||
"emoji_reactions": "Emoji Reactions",
|
||||
"reports": "Reports",
|
||||
"moves": "User migrates",
|
||||
"load_older": "Load older interactions"
|
||||
},
|
||||
|
@ -265,6 +270,16 @@
|
|||
"searching_for": "Searching for",
|
||||
"error": "Not found."
|
||||
},
|
||||
"report": {
|
||||
"reporter": "Reporter:",
|
||||
"reported_user": "Reported user:",
|
||||
"reported_statuses": "Reported statuses:",
|
||||
"notes": "Notes:",
|
||||
"state": "State:",
|
||||
"state_open": "Open",
|
||||
"state_closed": "Closed",
|
||||
"state_resolved": "Resolved"
|
||||
},
|
||||
"selectable_list": {
|
||||
"select_all": "Select all"
|
||||
},
|
||||
|
@ -299,6 +314,7 @@
|
|||
"desc": "To enable two-factor authentication, enter the code from your two-factor app:"
|
||||
}
|
||||
},
|
||||
"lists_navigation": "Show lists in navigation",
|
||||
"allow_following_move": "Allow auto-follow when following account moves",
|
||||
"attachmentRadius": "Attachments",
|
||||
"attachments": "Attachments",
|
||||
|
@ -954,6 +970,16 @@
|
|||
"error_sending_message": "Something went wrong when sending the message.",
|
||||
"empty_chat_list_placeholder": "You don't have any chats yet. Start a new chat!"
|
||||
},
|
||||
"lists": {
|
||||
"lists": "Lists",
|
||||
"new": "New List",
|
||||
"title": "List title",
|
||||
"search": "Search users",
|
||||
"create": "Create",
|
||||
"save": "Save changes",
|
||||
"delete": "Delete list",
|
||||
"following_only": "Limit to Following"
|
||||
},
|
||||
"file_type": {
|
||||
"audio": "Audio",
|
||||
"video": "Video",
|
||||
|
|
|
@ -744,6 +744,8 @@
|
|||
"favs_repeats": "Herhalingen en favorieten",
|
||||
"follows": "Nieuwe gevolgden",
|
||||
"moves": "Gebruikermigraties",
|
||||
"emoji_reactions": "Emoji Reacties",
|
||||
"reports": "Rapportages",
|
||||
"load_older": "Oudere interacties laden"
|
||||
},
|
||||
"remote_user_resolver": {
|
||||
|
@ -751,6 +753,17 @@
|
|||
"error": "Niet gevonden.",
|
||||
"remote_user_resolver": "Externe gebruikers-zoeker"
|
||||
},
|
||||
"report": {
|
||||
"reporter": "Reporteerder:",
|
||||
"reported_user": "Gerapporteerde gebruiker:",
|
||||
"reported_statuses": "Gerapporteerde statussen:",
|
||||
"notes": "Notas:",
|
||||
"state": "Status:",
|
||||
"state_open": "Open",
|
||||
"state_closed": "Gesloten",
|
||||
"state_resolved": "Opgelost"
|
||||
},
|
||||
|
||||
"selectable_list": {
|
||||
"select_all": "Alles selecteren"
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@ import './lib/event_target_polyfill.js'
|
|||
import interfaceModule from './modules/interface.js'
|
||||
import instanceModule from './modules/instance.js'
|
||||
import statusesModule from './modules/statuses.js'
|
||||
import listsModule from './modules/lists.js'
|
||||
import usersModule from './modules/users.js'
|
||||
import apiModule from './modules/api.js'
|
||||
import configModule from './modules/config.js'
|
||||
|
@ -72,6 +73,7 @@ const persistedStateOptions = {
|
|||
// TODO refactor users/statuses modules, they depend on each other
|
||||
users: usersModule,
|
||||
statuses: statusesModule,
|
||||
lists: listsModule,
|
||||
api: apiModule,
|
||||
config: configModule,
|
||||
serverSideConfig: serverSideConfigModule,
|
||||
|
|
|
@ -191,12 +191,13 @@ const api = {
|
|||
startFetchingTimeline (store, {
|
||||
timeline = 'friends',
|
||||
tag = false,
|
||||
userId = false
|
||||
userId = false,
|
||||
listId = false
|
||||
}) {
|
||||
if (store.state.fetchers[timeline]) return
|
||||
|
||||
const fetcher = store.state.backendInteractor.startFetchingTimeline({
|
||||
timeline, store, userId, tag
|
||||
timeline, store, userId, listId, tag
|
||||
})
|
||||
store.commit('addFetcher', { fetcherName: timeline, fetcher })
|
||||
},
|
||||
|
@ -248,6 +249,18 @@ const api = {
|
|||
store.commit('setFollowRequests', requests)
|
||||
},
|
||||
|
||||
// Lists
|
||||
startFetchingLists (store) {
|
||||
if (store.state.fetchers.lists) return
|
||||
const fetcher = store.state.backendInteractor.startFetchingLists({ store })
|
||||
store.commit('addFetcher', { fetcherName: 'lists', fetcher })
|
||||
},
|
||||
stopFetchingLists (store) {
|
||||
const fetcher = store.state.fetchers.lists
|
||||
if (!fetcher) return
|
||||
store.commit('removeFetcher', { fetcherName: 'lists', fetcher })
|
||||
},
|
||||
|
||||
// Pleroma websocket
|
||||
setWsToken (store, token) {
|
||||
store.commit('setWsToken', token)
|
||||
|
|
|
@ -59,6 +59,7 @@ export const defaultState = {
|
|||
moves: true,
|
||||
emojiReactions: true,
|
||||
followRequest: true,
|
||||
reports: true,
|
||||
chatMention: true,
|
||||
polls: true
|
||||
},
|
||||
|
@ -83,6 +84,10 @@ export const defaultState = {
|
|||
showScrollbars: false,
|
||||
userPopoverZoom: false,
|
||||
userPopoverOverlay: true,
|
||||
sidebarColumnWidth: '25rem',
|
||||
contentColumnWidth: '45rem',
|
||||
notifsColumnWidth: '25rem',
|
||||
listsNavigation: false,
|
||||
greentext: undefined, // instance default
|
||||
useAtIcon: undefined, // instance default
|
||||
mentionLinkDisplay: undefined, // instance default
|
||||
|
|
94
src/modules/lists.js
Normal file
94
src/modules/lists.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { remove, find } from 'lodash'
|
||||
|
||||
export const defaultState = {
|
||||
allLists: [],
|
||||
allListsObject: {}
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
setLists (state, value) {
|
||||
state.allLists = value
|
||||
},
|
||||
setList (state, { id, title }) {
|
||||
if (!state.allListsObject[id]) {
|
||||
state.allListsObject[id] = {}
|
||||
}
|
||||
state.allListsObject[id].title = title
|
||||
|
||||
if (!find(state.allLists, { id })) {
|
||||
state.allLists.push({ id, title })
|
||||
} else {
|
||||
find(state.allLists, { id }).title = title
|
||||
}
|
||||
},
|
||||
setListAccounts (state, { id, accountIds }) {
|
||||
if (!state.allListsObject[id]) {
|
||||
state.allListsObject[id] = {}
|
||||
}
|
||||
state.allListsObject[id].accountIds = accountIds
|
||||
},
|
||||
deleteList (state, { id }) {
|
||||
delete state.allListsObject[id]
|
||||
remove(state.allLists, list => list.id === id)
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
setLists ({ commit }, value) {
|
||||
commit('setLists', value)
|
||||
},
|
||||
createList ({ rootState, commit }, { title }) {
|
||||
return rootState.api.backendInteractor.createList({ title })
|
||||
.then((list) => {
|
||||
commit('setList', { id: list.id, title })
|
||||
return list
|
||||
})
|
||||
},
|
||||
fetchList ({ rootState, commit }, { id }) {
|
||||
return rootState.api.backendInteractor.getList({ id })
|
||||
.then((list) => commit('setList', { id: list.id, title: list.title }))
|
||||
},
|
||||
fetchListAccounts ({ rootState, commit }, { id }) {
|
||||
return rootState.api.backendInteractor.getListAccounts({ id })
|
||||
.then((accountIds) => commit('setListAccounts', { id, accountIds }))
|
||||
},
|
||||
setList ({ rootState, commit }, { id, title }) {
|
||||
rootState.api.backendInteractor.updateList({ id, title })
|
||||
commit('setList', { id, title })
|
||||
},
|
||||
setListAccounts ({ rootState, commit }, { id, accountIds }) {
|
||||
const saved = rootState.lists.allListsObject[id].accountIds || []
|
||||
const added = accountIds.filter(id => !saved.includes(id))
|
||||
const removed = saved.filter(id => !accountIds.includes(id))
|
||||
commit('setListAccounts', { id, accountIds })
|
||||
if (added.length > 0) {
|
||||
rootState.api.backendInteractor.addAccountsToList({ id, accountIds: added })
|
||||
}
|
||||
if (removed.length > 0) {
|
||||
rootState.api.backendInteractor.removeAccountsFromList({ id, accountIds: removed })
|
||||
}
|
||||
},
|
||||
deleteList ({ rootState, commit }, { id }) {
|
||||
rootState.api.backendInteractor.deleteList({ id })
|
||||
commit('deleteList', { id })
|
||||
}
|
||||
}
|
||||
|
||||
export const getters = {
|
||||
findListTitle: state => id => {
|
||||
if (!state.allListsObject[id]) return
|
||||
return state.allListsObject[id].title
|
||||
},
|
||||
findListAccounts: state => id => {
|
||||
return [...state.allListsObject[id].accountIds]
|
||||
}
|
||||
}
|
||||
|
||||
const lists = {
|
||||
state: defaultState,
|
||||
mutations,
|
||||
actions,
|
||||
getters
|
||||
}
|
||||
|
||||
export default lists
|
|
@ -2,20 +2,29 @@ import filter from 'lodash/filter'
|
|||
|
||||
const reports = {
|
||||
state: {
|
||||
userId: null,
|
||||
statuses: [],
|
||||
preTickedIds: [],
|
||||
modalActivated: false
|
||||
reportModal: {
|
||||
userId: null,
|
||||
statuses: [],
|
||||
preTickedIds: [],
|
||||
activated: false
|
||||
},
|
||||
reports: {}
|
||||
},
|
||||
mutations: {
|
||||
openUserReportingModal (state, { userId, statuses, preTickedIds }) {
|
||||
state.userId = userId
|
||||
state.statuses = statuses
|
||||
state.preTickedIds = preTickedIds
|
||||
state.modalActivated = true
|
||||
state.reportModal.userId = userId
|
||||
state.reportModal.statuses = statuses
|
||||
state.reportModal.preTickedIds = preTickedIds
|
||||
state.reportModal.activated = true
|
||||
},
|
||||
closeUserReportingModal (state) {
|
||||
state.modalActivated = false
|
||||
state.reportModal.activated = false
|
||||
},
|
||||
setReportState (reportsState, { id, state }) {
|
||||
reportsState.reports[id].state = state
|
||||
},
|
||||
addReport (state, report) {
|
||||
state.reports[report.id] = report
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
@ -31,6 +40,23 @@ const reports = {
|
|||
},
|
||||
closeUserReportingModal ({ commit }) {
|
||||
commit('closeUserReportingModal')
|
||||
},
|
||||
setReportState ({ commit, dispatch, rootState }, { id, state }) {
|
||||
const oldState = rootState.reports.reports[id].state
|
||||
commit('setReportState', { id, state })
|
||||
rootState.api.backendInteractor.setReportState({ id, state }).catch(e => {
|
||||
console.error('Failed to set report state', e)
|
||||
dispatch('pushGlobalNotice', {
|
||||
level: 'error',
|
||||
messageKey: 'general.generic_error_message',
|
||||
messageArgs: [e.message],
|
||||
timeout: 5000
|
||||
})
|
||||
commit('setReportState', { id, state: oldState })
|
||||
})
|
||||
},
|
||||
addReport ({ commit }, report) {
|
||||
commit('addReport', report)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ export const defaultState = () => ({
|
|||
friends: emptyTl(),
|
||||
tag: emptyTl(),
|
||||
dms: emptyTl(),
|
||||
bookmarks: emptyTl()
|
||||
bookmarks: emptyTl(),
|
||||
list: emptyTl()
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -336,6 +337,10 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
|
|||
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
|
||||
}
|
||||
|
||||
if (notification.type === 'pleroma:report') {
|
||||
dispatch('addReport', notification.report)
|
||||
}
|
||||
|
||||
if (notification.type === 'pleroma:emoji_reaction') {
|
||||
dispatch('fetchEmojiReactionsBy', notification.status.id)
|
||||
}
|
||||
|
|
|
@ -52,6 +52,9 @@ const MASTODON_STATUS_CONTEXT_URL = id => `/api/v1/statuses/${id}/context`
|
|||
const MASTODON_USER_URL = '/api/v1/accounts'
|
||||
const MASTODON_USER_RELATIONSHIPS_URL = '/api/v1/accounts/relationships'
|
||||
const MASTODON_USER_TIMELINE_URL = id => `/api/v1/accounts/${id}/statuses`
|
||||
const MASTODON_LIST_URL = id => `/api/v1/lists/${id}`
|
||||
const MASTODON_LIST_TIMELINE_URL = id => `/api/v1/timelines/list/${id}`
|
||||
const MASTODON_LIST_ACCOUNTS_URL = id => `/api/v1/lists/${id}/accounts`
|
||||
const MASTODON_TAG_TIMELINE_URL = tag => `/api/v1/timelines/tag/${tag}`
|
||||
const MASTODON_BOOKMARK_TIMELINE_URL = '/api/v1/bookmarks'
|
||||
const MASTODON_USER_BLOCKS_URL = '/api/v1/blocks/'
|
||||
|
@ -79,6 +82,7 @@ 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_LISTS_URL = '/api/v1/lists'
|
||||
const MASTODON_STREAMING = '/api/v1/streaming'
|
||||
const MASTODON_KNOWN_DOMAIN_LIST_URL = '/api/v1/instance/peers'
|
||||
const PLEROMA_EMOJI_REACTIONS_URL = id => `/api/v1/pleroma/statuses/${id}/reactions`
|
||||
|
@ -89,6 +93,7 @@ const PLEROMA_CHAT_URL = id => `/api/v1/pleroma/chats/by-account-id/${id}`
|
|||
const PLEROMA_CHAT_MESSAGES_URL = id => `/api/v1/pleroma/chats/${id}/messages`
|
||||
const PLEROMA_CHAT_READ_URL = id => `/api/v1/pleroma/chats/${id}/read`
|
||||
const PLEROMA_DELETE_CHAT_MESSAGE_URL = (chatId, messageId) => `/api/v1/pleroma/chats/${chatId}/messages/${messageId}`
|
||||
const PLEROMA_ADMIN_REPORTS = '/api/pleroma/admin/reports'
|
||||
const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
|
||||
|
||||
const oldfetch = window.fetch
|
||||
|
@ -385,6 +390,81 @@ const fetchFollowRequests = ({ credentials }) => {
|
|||
.then((data) => data.map(parseUser))
|
||||
}
|
||||
|
||||
const fetchLists = ({ credentials }) => {
|
||||
const url = MASTODON_LISTS_URL
|
||||
return fetch(url, { headers: authHeaders(credentials) })
|
||||
.then((data) => data.json())
|
||||
}
|
||||
|
||||
const createList = ({ title, credentials }) => {
|
||||
const url = MASTODON_LISTS_URL
|
||||
const headers = authHeaders(credentials)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
return fetch(url, {
|
||||
headers,
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ title })
|
||||
}).then((data) => data.json())
|
||||
}
|
||||
|
||||
const getList = ({ id, credentials }) => {
|
||||
const url = MASTODON_LIST_URL(id)
|
||||
return fetch(url, { headers: authHeaders(credentials) })
|
||||
.then((data) => data.json())
|
||||
}
|
||||
|
||||
const updateList = ({ id, title, credentials }) => {
|
||||
const url = MASTODON_LIST_URL(id)
|
||||
const headers = authHeaders(credentials)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
return fetch(url, {
|
||||
headers,
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ title })
|
||||
})
|
||||
}
|
||||
|
||||
const getListAccounts = ({ id, credentials }) => {
|
||||
const url = MASTODON_LIST_ACCOUNTS_URL(id)
|
||||
return fetch(url, { headers: authHeaders(credentials) })
|
||||
.then((data) => data.json())
|
||||
.then((data) => data.map(({ id }) => id))
|
||||
}
|
||||
|
||||
const addAccountsToList = ({ id, accountIds, credentials }) => {
|
||||
const url = MASTODON_LIST_ACCOUNTS_URL(id)
|
||||
const headers = authHeaders(credentials)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
return fetch(url, {
|
||||
headers,
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ account_ids: accountIds })
|
||||
})
|
||||
}
|
||||
|
||||
const removeAccountsFromList = ({ id, accountIds, credentials }) => {
|
||||
const url = MASTODON_LIST_ACCOUNTS_URL(id)
|
||||
const headers = authHeaders(credentials)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
return fetch(url, {
|
||||
headers,
|
||||
method: 'DELETE',
|
||||
body: JSON.stringify({ account_ids: accountIds })
|
||||
})
|
||||
}
|
||||
|
||||
const deleteList = ({ id, credentials }) => {
|
||||
const url = MASTODON_LIST_URL(id)
|
||||
return fetch(url, {
|
||||
method: 'DELETE',
|
||||
headers: authHeaders(credentials)
|
||||
})
|
||||
}
|
||||
|
||||
const fetchConversation = ({ id, credentials }) => {
|
||||
const urlContext = MASTODON_STATUS_CONTEXT_URL(id)
|
||||
return fetch(urlContext, { headers: authHeaders(credentials) })
|
||||
|
@ -506,9 +586,11 @@ const fetchTimeline = ({
|
|||
since = false,
|
||||
until = false,
|
||||
userId = false,
|
||||
listId = false,
|
||||
tag = false,
|
||||
withMuted = false,
|
||||
replyVisibility = 'all'
|
||||
replyVisibility = 'all',
|
||||
includeTypes = []
|
||||
}) => {
|
||||
const timelineUrls = {
|
||||
public: MASTODON_PUBLIC_TIMELINE,
|
||||
|
@ -518,6 +600,7 @@ const fetchTimeline = ({
|
|||
publicAndExternal: MASTODON_PUBLIC_TIMELINE,
|
||||
user: MASTODON_USER_TIMELINE_URL,
|
||||
media: MASTODON_USER_TIMELINE_URL,
|
||||
list: MASTODON_LIST_TIMELINE_URL,
|
||||
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
|
||||
tag: MASTODON_TAG_TIMELINE_URL,
|
||||
bookmarks: MASTODON_BOOKMARK_TIMELINE_URL
|
||||
|
@ -531,6 +614,10 @@ const fetchTimeline = ({
|
|||
url = url(userId)
|
||||
}
|
||||
|
||||
if (timeline === 'list') {
|
||||
url = url(listId)
|
||||
}
|
||||
|
||||
if (since) {
|
||||
params.push(['since_id', since])
|
||||
}
|
||||
|
@ -555,6 +642,11 @@ const fetchTimeline = ({
|
|||
if (replyVisibility !== 'all') {
|
||||
params.push(['reply_visibility', replyVisibility])
|
||||
}
|
||||
if (includeTypes.length > 0) {
|
||||
includeTypes.forEach(type => {
|
||||
params.push(['include_types[]', type])
|
||||
})
|
||||
}
|
||||
|
||||
params.push(['limit', 20])
|
||||
|
||||
|
@ -1339,6 +1431,38 @@ const deleteChatMessage = ({ chatId, messageId, credentials }) => {
|
|||
})
|
||||
}
|
||||
|
||||
const setReportState = ({ id, state, credentials }) => {
|
||||
// TODO: Can't use promisedRequest because on OK this does not return json
|
||||
// See https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1322
|
||||
return fetch(PLEROMA_ADMIN_REPORTS, {
|
||||
headers: {
|
||||
...authHeaders(credentials),
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify({
|
||||
reports: [{
|
||||
id,
|
||||
state
|
||||
}]
|
||||
})
|
||||
})
|
||||
.then(data => {
|
||||
if (data.status >= 500) {
|
||||
throw Error(data.statusText)
|
||||
} else if (data.status >= 400) {
|
||||
return data.json()
|
||||
}
|
||||
return data
|
||||
})
|
||||
.then(data => {
|
||||
if (data.errors) {
|
||||
throw Error(data.errors[0].message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const apiService = {
|
||||
verifyCredentials,
|
||||
fetchTimeline,
|
||||
|
@ -1405,6 +1529,14 @@ const apiService = {
|
|||
addBackup,
|
||||
listBackups,
|
||||
fetchFollowRequests,
|
||||
fetchLists,
|
||||
createList,
|
||||
getList,
|
||||
updateList,
|
||||
getListAccounts,
|
||||
addAccountsToList,
|
||||
removeAccountsFromList,
|
||||
deleteList,
|
||||
approveUser,
|
||||
denyUser,
|
||||
suggestions,
|
||||
|
@ -1430,7 +1562,8 @@ const apiService = {
|
|||
chatMessages,
|
||||
sendChatMessage,
|
||||
readChat,
|
||||
deleteChatMessage
|
||||
deleteChatMessage,
|
||||
setReportState
|
||||
}
|
||||
|
||||
export default apiService
|
||||
|
|
|
@ -2,10 +2,11 @@ import apiService, { getMastodonSocketURI, ProcessedWS } from '../api/api.servic
|
|||
import timelineFetcher from '../timeline_fetcher/timeline_fetcher.service.js'
|
||||
import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js'
|
||||
import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service'
|
||||
import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js'
|
||||
|
||||
const backendInteractorService = credentials => ({
|
||||
startFetchingTimeline ({ timeline, store, userId = false, tag }) {
|
||||
return timelineFetcher.startFetching({ timeline, store, credentials, userId, tag })
|
||||
startFetchingTimeline ({ timeline, store, userId = false, listId = false, tag }) {
|
||||
return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, tag })
|
||||
},
|
||||
|
||||
fetchTimeline (args) {
|
||||
|
@ -24,6 +25,10 @@ const backendInteractorService = credentials => ({
|
|||
return followRequestFetcher.startFetching({ store, credentials })
|
||||
},
|
||||
|
||||
startFetchingLists ({ store }) {
|
||||
return listsFetcher.startFetching({ store, credentials })
|
||||
},
|
||||
|
||||
startUserSocket ({ store }) {
|
||||
const serv = store.rootState.instance.server.replace('http', 'ws')
|
||||
const url = serv + getMastodonSocketURI({ credentials, stream: 'user' })
|
||||
|
|
|
@ -390,6 +390,13 @@ export const parseNotification = (data) => {
|
|||
: parseUser(data.target)
|
||||
output.from_profile = parseUser(data.account)
|
||||
output.emoji = data.emoji
|
||||
if (data.report) {
|
||||
output.report = data.report
|
||||
output.report.content = data.report.content
|
||||
output.report.acct = parseUser(data.report.account)
|
||||
output.report.actor = parseUser(data.report.actor)
|
||||
output.report.statuses = data.report.statuses.map(parseStatus)
|
||||
}
|
||||
} else {
|
||||
const parsedNotice = parseStatus(data.notice)
|
||||
output.type = data.ntype
|
||||
|
|
22
src/services/lists_fetcher/lists_fetcher.service.js
Normal file
22
src/services/lists_fetcher/lists_fetcher.service.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import apiService from '../api/api.service.js'
|
||||
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
||||
|
||||
const fetchAndUpdate = ({ store, credentials }) => {
|
||||
return apiService.fetchLists({ credentials })
|
||||
.then(lists => {
|
||||
store.commit('setLists', lists)
|
||||
}, () => {})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const startFetching = ({ credentials, store }) => {
|
||||
const boundFetchAndUpdate = () => fetchAndUpdate({ credentials, store })
|
||||
boundFetchAndUpdate()
|
||||
return promiseInterval(boundFetchAndUpdate, 240000)
|
||||
}
|
||||
|
||||
const listsFetcher = {
|
||||
startFetching
|
||||
}
|
||||
|
||||
export default listsFetcher
|
|
@ -15,6 +15,7 @@ export const visibleTypes = store => {
|
|||
rootState.config.notificationVisibility.followRequest && 'follow_request',
|
||||
rootState.config.notificationVisibility.moves && 'move',
|
||||
rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction',
|
||||
rootState.config.notificationVisibility.reports && 'pleroma:report',
|
||||
rootState.config.notificationVisibility.polls && 'poll'
|
||||
].filter(_ => _))
|
||||
}
|
||||
|
@ -99,6 +100,9 @@ export const prepareNotificationObject = (notification, i18n) => {
|
|||
case 'follow_request':
|
||||
i18nString = 'follow_request'
|
||||
break
|
||||
case 'pleroma:report':
|
||||
i18nString = 'submitted_report'
|
||||
break
|
||||
case 'poll':
|
||||
i18nString = 'poll_ended'
|
||||
break
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
import apiService from '../api/api.service.js'
|
||||
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
||||
|
||||
// For using include_types when fetching notifications.
|
||||
// Note: chat_mention excluded as pleroma-fe polls them separately
|
||||
const mastoApiNotificationTypes = [
|
||||
'mention',
|
||||
'favourite',
|
||||
'reblog',
|
||||
'follow',
|
||||
'move',
|
||||
'pleroma:emoji_reaction',
|
||||
'pleroma:report'
|
||||
]
|
||||
|
||||
const update = ({ store, notifications, older }) => {
|
||||
store.dispatch('addNewNotifications', { notifications, older })
|
||||
}
|
||||
|
@ -12,6 +24,7 @@ const fetchAndUpdate = ({ store, credentials, older = false, since }) => {
|
|||
const timelineData = rootState.statuses.notifications
|
||||
const hideMutedPosts = getters.mergedConfig.hideMutedPosts
|
||||
|
||||
args.includeTypes = mastoApiNotificationTypes
|
||||
args.withMuted = !hideMutedPosts
|
||||
|
||||
args.timeline = 'notifications'
|
||||
|
@ -63,6 +76,7 @@ const fetchNotifications = ({ store, args, older }) => {
|
|||
messageArgs: [error.message],
|
||||
timeout: 5000
|
||||
})
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,13 @@ import { camelCase } from 'lodash'
|
|||
import apiService from '../api/api.service.js'
|
||||
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
||||
|
||||
const update = ({ store, statuses, timeline, showImmediately, userId, pagination }) => {
|
||||
const update = ({ store, statuses, timeline, showImmediately, userId, listId, pagination }) => {
|
||||
const ccTimeline = camelCase(timeline)
|
||||
|
||||
store.dispatch('addNewStatuses', {
|
||||
timeline: ccTimeline,
|
||||
userId,
|
||||
listId,
|
||||
statuses,
|
||||
showImmediately,
|
||||
pagination
|
||||
|
@ -22,6 +23,7 @@ const fetchAndUpdate = ({
|
|||
older = false,
|
||||
showImmediately = false,
|
||||
userId = false,
|
||||
listId = false,
|
||||
tag = false,
|
||||
until,
|
||||
since
|
||||
|
@ -44,6 +46,7 @@ const fetchAndUpdate = ({
|
|||
}
|
||||
|
||||
args.userId = userId
|
||||
args.listId = listId
|
||||
args.tag = tag
|
||||
args.withMuted = !hideMutedPosts
|
||||
if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) {
|
||||
|
@ -62,7 +65,7 @@ const fetchAndUpdate = ({
|
|||
if (!older && statuses.length >= 20 && !timelineData.loading && numStatusesBeforeFetch > 0) {
|
||||
store.dispatch('queueFlush', { timeline, id: timelineData.maxId })
|
||||
}
|
||||
update({ store, statuses, timeline, showImmediately, userId, pagination })
|
||||
update({ store, statuses, timeline, showImmediately, userId, listId, pagination })
|
||||
return { statuses, pagination }
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -75,14 +78,15 @@ const fetchAndUpdate = ({
|
|||
})
|
||||
}
|
||||
|
||||
const startFetching = ({ timeline = 'friends', credentials, store, userId = false, tag = false }) => {
|
||||
const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, tag = false }) => {
|
||||
const rootState = store.rootState || store.state
|
||||
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
|
||||
const showImmediately = timelineData.visibleStatuses.length === 0
|
||||
timelineData.userId = userId
|
||||
fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, tag })
|
||||
timelineData.listId = listId
|
||||
fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, tag })
|
||||
const boundFetchAndUpdate = () =>
|
||||
fetchAndUpdate({ timeline, credentials, store, userId, tag })
|
||||
fetchAndUpdate({ timeline, credentials, store, userId, listId, tag })
|
||||
return promiseInterval(boundFetchAndUpdate, 10000)
|
||||
}
|
||||
const timelineFetcher = {
|
||||
|
|
|
@ -40,4 +40,28 @@ describe('routes', () => {
|
|||
// eslint-disable-next-line no-prototype-builtins
|
||||
expect(matchedComponents[0].components.default.components.hasOwnProperty('UserCard')).to.eql(true)
|
||||
})
|
||||
|
||||
it('list view', async () => {
|
||||
await router.push('/lists')
|
||||
|
||||
const matchedComponents = router.currentRoute.value.matched
|
||||
|
||||
expect(Object.prototype.hasOwnProperty.call(matchedComponents[0].components.default.components, 'ListsCard')).to.eql(true)
|
||||
})
|
||||
|
||||
it('list timeline', async () => {
|
||||
await router.push('/lists/1')
|
||||
|
||||
const matchedComponents = router.currentRoute.value.matched
|
||||
|
||||
expect(Object.prototype.hasOwnProperty.call(matchedComponents[0].components.default.components, 'Timeline')).to.eql(true)
|
||||
})
|
||||
|
||||
it('list edit', async () => {
|
||||
await router.push('/lists/1/edit')
|
||||
|
||||
const matchedComponents = router.currentRoute.value.matched
|
||||
|
||||
expect(Object.prototype.hasOwnProperty.call(matchedComponents[0].components.default.components, 'BasicUserCard')).to.eql(true)
|
||||
})
|
||||
})
|
||||
|
|
83
test/unit/specs/modules/lists.spec.js
Normal file
83
test/unit/specs/modules/lists.spec.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
import { cloneDeep } from 'lodash'
|
||||
import { defaultState, mutations, getters } from '../../../../src/modules/lists.js'
|
||||
|
||||
describe('The lists module', () => {
|
||||
describe('mutations', () => {
|
||||
it('updates array of all lists', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const list = { id: '1', title: 'testList' }
|
||||
|
||||
mutations.setLists(state, [list])
|
||||
expect(state.allLists).to.have.length(1)
|
||||
expect(state.allLists).to.eql([list])
|
||||
})
|
||||
|
||||
it('adds a new list with a title, updating the title for existing lists', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const list = { id: '1', title: 'testList' }
|
||||
const modList = { id: '1', title: 'anotherTestTitle' }
|
||||
|
||||
mutations.setList(state, list)
|
||||
expect(state.allListsObject[list.id]).to.eql({ title: list.title })
|
||||
expect(state.allLists).to.have.length(1)
|
||||
expect(state.allLists[0]).to.eql(list)
|
||||
|
||||
mutations.setList(state, modList)
|
||||
expect(state.allListsObject[modList.id]).to.eql({ title: modList.title })
|
||||
expect(state.allLists).to.have.length(1)
|
||||
expect(state.allLists[0]).to.eql(modList)
|
||||
})
|
||||
|
||||
it('adds a new list with an array of IDs, updating the IDs for existing lists', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const list = { id: '1', accountIds: ['1', '2', '3'] }
|
||||
const modList = { id: '1', accountIds: ['3', '4', '5'] }
|
||||
|
||||
mutations.setListAccounts(state, list)
|
||||
expect(state.allListsObject[list.id]).to.eql({ accountIds: list.accountIds })
|
||||
|
||||
mutations.setListAccounts(state, modList)
|
||||
expect(state.allListsObject[modList.id]).to.eql({ accountIds: modList.accountIds })
|
||||
})
|
||||
|
||||
it('deletes a list', () => {
|
||||
const state = {
|
||||
allLists: [{ id: '1', title: 'testList' }],
|
||||
allListsObject: {
|
||||
1: { title: 'testList', accountIds: ['1', '2', '3'] }
|
||||
}
|
||||
}
|
||||
const id = '1'
|
||||
|
||||
mutations.deleteList(state, { id })
|
||||
expect(state.allLists).to.have.length(0)
|
||||
expect(state.allListsObject).to.eql({})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getters', () => {
|
||||
it('returns list title', () => {
|
||||
const state = {
|
||||
allLists: [{ id: '1', title: 'testList' }],
|
||||
allListsObject: {
|
||||
1: { title: 'testList', accountIds: ['1', '2', '3'] }
|
||||
}
|
||||
}
|
||||
const id = '1'
|
||||
|
||||
expect(getters.findListTitle(state)(id)).to.eql('testList')
|
||||
})
|
||||
|
||||
it('returns list accounts', () => {
|
||||
const state = {
|
||||
allLists: [{ id: '1', title: 'testList' }],
|
||||
allListsObject: {
|
||||
1: { title: 'testList', accountIds: ['1', '2', '3'] }
|
||||
}
|
||||
}
|
||||
const id = '1'
|
||||
|
||||
expect(getters.findListAccounts(state)(id)).to.eql(['1', '2', '3'])
|
||||
})
|
||||
})
|
||||
})
|
239
yarn.lock
239
yarn.lock
|
@ -30,7 +30,7 @@
|
|||
dependencies:
|
||||
"@babel/highlight" "^7.18.6"
|
||||
|
||||
"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.7":
|
||||
"@babel/compat-data@^7.17.7":
|
||||
version "7.17.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2"
|
||||
integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==
|
||||
|
@ -40,21 +40,21 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
|
||||
integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==
|
||||
|
||||
"@babel/core@7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.9.tgz#805461f967c77ff46c74ca0460ccf4fe933ddd59"
|
||||
integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==
|
||||
"@babel/core@7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8"
|
||||
integrity sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.1.0"
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/generator" "^7.18.9"
|
||||
"@babel/generator" "^7.18.10"
|
||||
"@babel/helper-compilation-targets" "^7.18.9"
|
||||
"@babel/helper-module-transforms" "^7.18.9"
|
||||
"@babel/helpers" "^7.18.9"
|
||||
"@babel/parser" "^7.18.9"
|
||||
"@babel/template" "^7.18.6"
|
||||
"@babel/traverse" "^7.18.9"
|
||||
"@babel/types" "^7.18.9"
|
||||
"@babel/parser" "^7.18.10"
|
||||
"@babel/template" "^7.18.10"
|
||||
"@babel/traverse" "^7.18.10"
|
||||
"@babel/types" "^7.18.10"
|
||||
convert-source-map "^1.7.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
|
@ -100,6 +100,15 @@
|
|||
jsesc "^2.5.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.10.tgz#794f328bfabdcbaf0ebf9bf91b5b57b61fa77a2a"
|
||||
integrity sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.18.10"
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/generator@^7.18.6", "@babel/generator@^7.18.7":
|
||||
version "7.18.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.7.tgz#2aa78da3c05aadfc82dbac16c99552fc802284bd"
|
||||
|
@ -140,14 +149,14 @@
|
|||
"@babel/helper-explode-assignable-expression" "^7.18.6"
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.13.0":
|
||||
version "7.17.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46"
|
||||
integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==
|
||||
"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf"
|
||||
integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.17.7"
|
||||
"@babel/helper-validator-option" "^7.16.7"
|
||||
browserslist "^4.17.5"
|
||||
"@babel/compat-data" "^7.18.8"
|
||||
"@babel/helper-validator-option" "^7.18.6"
|
||||
browserslist "^4.20.2"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.18.6":
|
||||
|
@ -160,16 +169,6 @@
|
|||
browserslist "^4.20.2"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf"
|
||||
integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.18.8"
|
||||
"@babel/helper-validator-option" "^7.18.6"
|
||||
browserslist "^4.20.2"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz#6f15f8459f3b523b39e00a99982e2c040871ed72"
|
||||
|
@ -199,15 +198,13 @@
|
|||
"@babel/helper-annotate-as-pure" "^7.18.6"
|
||||
regexpu-core "^5.1.0"
|
||||
|
||||
"@babel/helper-define-polyfill-provider@^0.3.1":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665"
|
||||
integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==
|
||||
"@babel/helper-define-polyfill-provider@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz#bd10d0aca18e8ce012755395b05a79f45eca5073"
|
||||
integrity sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==
|
||||
dependencies:
|
||||
"@babel/helper-compilation-targets" "^7.13.0"
|
||||
"@babel/helper-module-imports" "^7.12.13"
|
||||
"@babel/helper-plugin-utils" "^7.13.0"
|
||||
"@babel/traverse" "^7.13.0"
|
||||
"@babel/helper-compilation-targets" "^7.17.7"
|
||||
"@babel/helper-plugin-utils" "^7.16.7"
|
||||
debug "^4.1.1"
|
||||
lodash.debounce "^4.0.8"
|
||||
resolve "^1.14.2"
|
||||
|
@ -310,13 +307,6 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.0.0"
|
||||
|
||||
"@babel/helper-module-imports@^7.12.13":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437"
|
||||
integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.7"
|
||||
|
||||
"@babel/helper-module-imports@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
|
||||
|
@ -364,7 +354,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250"
|
||||
integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==
|
||||
|
||||
"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
|
||||
"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
|
||||
integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==
|
||||
|
@ -389,6 +379,16 @@
|
|||
"@babel/helper-wrap-function" "^7.18.6"
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-remap-async-to-generator@^7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519"
|
||||
integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.18.6"
|
||||
"@babel/helper-environment-visitor" "^7.18.9"
|
||||
"@babel/helper-wrap-function" "^7.18.9"
|
||||
"@babel/types" "^7.18.9"
|
||||
|
||||
"@babel/helper-replace-supers@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz#efedf51cfccea7b7b8c0f00002ab317e7abfe420"
|
||||
|
@ -439,6 +439,11 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-string-parser@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
|
||||
integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.16.7":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
|
||||
|
@ -449,11 +454,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
|
||||
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
|
||||
|
||||
"@babel/helper-validator-option@^7.16.7":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23"
|
||||
integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==
|
||||
|
||||
"@babel/helper-validator-option@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
|
||||
|
@ -469,6 +469,16 @@
|
|||
"@babel/traverse" "^7.18.6"
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-wrap-function@^7.18.9":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.10.tgz#a7fcd3ab9b1be4c9b52cf7d7fdc1e88c2ce93396"
|
||||
integrity sha512-95NLBP59VWdfK2lyLKe6eTMq9xg+yWKzxzxbJ1wcYNi1Auz200+83fMDADjRxBvc2QQor5zja2yTQzXGhk2GtQ==
|
||||
dependencies:
|
||||
"@babel/helper-function-name" "^7.18.9"
|
||||
"@babel/template" "^7.18.10"
|
||||
"@babel/traverse" "^7.18.10"
|
||||
"@babel/types" "^7.18.10"
|
||||
|
||||
"@babel/helpers@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.6.tgz#4c966140eaa1fcaa3d5a8c09d7db61077d4debfd"
|
||||
|
@ -523,6 +533,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.7.tgz#fc19b645a5456c8d6fdb6cecd3c66c0173902800"
|
||||
integrity sha512-bm3AQf45vR4gKggRfvJdYJ0gFLoCbsPxiFLSH6hTVYABptNHY6l9NrhnucVjQ/X+SPtLANT9lc0fFhikj+VBRA==
|
||||
|
||||
"@babel/parser@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.10.tgz#94b5f8522356e69e8277276adf67ed280c90ecc1"
|
||||
integrity sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg==
|
||||
|
||||
"@babel/parser@^7.18.6", "@babel/parser@^7.18.8":
|
||||
version "7.18.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.8.tgz#822146080ac9c62dac0823bb3489622e0bc1cbdf"
|
||||
|
@ -549,14 +564,14 @@
|
|||
"@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
|
||||
"@babel/plugin-proposal-optional-chaining" "^7.18.9"
|
||||
|
||||
"@babel/plugin-proposal-async-generator-functions@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz#aedac81e6fc12bb643374656dd5f2605bf743d17"
|
||||
integrity sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==
|
||||
"@babel/plugin-proposal-async-generator-functions@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz#85ea478c98b0095c3e4102bff3b67d306ed24952"
|
||||
integrity sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==
|
||||
dependencies:
|
||||
"@babel/helper-environment-visitor" "^7.18.6"
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
"@babel/helper-remap-async-to-generator" "^7.18.6"
|
||||
"@babel/helper-environment-visitor" "^7.18.9"
|
||||
"@babel/helper-plugin-utils" "^7.18.9"
|
||||
"@babel/helper-remap-async-to-generator" "^7.18.9"
|
||||
"@babel/plugin-syntax-async-generators" "^7.8.4"
|
||||
|
||||
"@babel/plugin-proposal-class-properties@^7.18.6":
|
||||
|
@ -1007,16 +1022,16 @@
|
|||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
|
||||
"@babel/plugin-transform-runtime@7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.9.tgz#d9e4b1b25719307bfafbf43065ed7fb3a83adb8f"
|
||||
integrity sha512-wS8uJwBt7/b/mzE13ktsJdmS4JP/j7PQSaADtnb4I2wL0zK51MQ0pmF8/Jy0wUIS96fr+fXT6S/ifiPXnvrlSg==
|
||||
"@babel/plugin-transform-runtime@7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz#37d14d1fa810a368fd635d4d1476c0154144a96f"
|
||||
integrity sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.18.6"
|
||||
"@babel/helper-plugin-utils" "^7.18.9"
|
||||
babel-plugin-polyfill-corejs2 "^0.3.1"
|
||||
babel-plugin-polyfill-corejs3 "^0.5.2"
|
||||
babel-plugin-polyfill-regenerator "^0.3.1"
|
||||
babel-plugin-polyfill-corejs2 "^0.3.2"
|
||||
babel-plugin-polyfill-corejs3 "^0.5.3"
|
||||
babel-plugin-polyfill-regenerator "^0.4.0"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/plugin-transform-shorthand-properties@^7.18.6":
|
||||
|
@ -1055,12 +1070,12 @@
|
|||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.18.9"
|
||||
|
||||
"@babel/plugin-transform-unicode-escapes@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz#0d01fb7fb2243ae1c033f65f6e3b4be78db75f27"
|
||||
integrity sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==
|
||||
"@babel/plugin-transform-unicode-escapes@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246"
|
||||
integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
"@babel/helper-plugin-utils" "^7.18.9"
|
||||
|
||||
"@babel/plugin-transform-unicode-regex@^7.18.6":
|
||||
version "7.18.6"
|
||||
|
@ -1070,10 +1085,10 @@
|
|||
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
|
||||
"@babel/preset-env@7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.9.tgz#9b3425140d724fbe590322017466580844c7eaff"
|
||||
integrity sha512-75pt/q95cMIHWssYtyfjVlvI+QEZQThQbKvR9xH+F/Agtw/s4Wfc2V9Bwd/P39VtixB7oWxGdH4GteTTwYJWMg==
|
||||
"@babel/preset-env@7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.10.tgz#83b8dfe70d7eea1aae5a10635ab0a5fe60dfc0f4"
|
||||
integrity sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.18.8"
|
||||
"@babel/helper-compilation-targets" "^7.18.9"
|
||||
|
@ -1081,7 +1096,7 @@
|
|||
"@babel/helper-validator-option" "^7.18.6"
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6"
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9"
|
||||
"@babel/plugin-proposal-async-generator-functions" "^7.18.6"
|
||||
"@babel/plugin-proposal-async-generator-functions" "^7.18.10"
|
||||
"@babel/plugin-proposal-class-properties" "^7.18.6"
|
||||
"@babel/plugin-proposal-class-static-block" "^7.18.6"
|
||||
"@babel/plugin-proposal-dynamic-import" "^7.18.6"
|
||||
|
@ -1141,13 +1156,13 @@
|
|||
"@babel/plugin-transform-sticky-regex" "^7.18.6"
|
||||
"@babel/plugin-transform-template-literals" "^7.18.9"
|
||||
"@babel/plugin-transform-typeof-symbol" "^7.18.9"
|
||||
"@babel/plugin-transform-unicode-escapes" "^7.18.6"
|
||||
"@babel/plugin-transform-unicode-escapes" "^7.18.10"
|
||||
"@babel/plugin-transform-unicode-regex" "^7.18.6"
|
||||
"@babel/preset-modules" "^0.1.5"
|
||||
"@babel/types" "^7.18.9"
|
||||
babel-plugin-polyfill-corejs2 "^0.3.1"
|
||||
babel-plugin-polyfill-corejs3 "^0.5.2"
|
||||
babel-plugin-polyfill-regenerator "^0.3.1"
|
||||
"@babel/types" "^7.18.10"
|
||||
babel-plugin-polyfill-corejs2 "^0.3.2"
|
||||
babel-plugin-polyfill-corejs3 "^0.5.3"
|
||||
babel-plugin-polyfill-regenerator "^0.4.0"
|
||||
core-js-compat "^3.22.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
|
@ -1196,6 +1211,15 @@
|
|||
"@babel/parser" "^7.16.7"
|
||||
"@babel/types" "^7.16.7"
|
||||
|
||||
"@babel/template@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
|
||||
integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/parser" "^7.18.10"
|
||||
"@babel/types" "^7.18.10"
|
||||
|
||||
"@babel/template@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
|
||||
|
@ -1205,7 +1229,7 @@
|
|||
"@babel/parser" "^7.18.6"
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/traverse@^7.0.0", "@babel/traverse@^7.13.0":
|
||||
"@babel/traverse@^7.0.0":
|
||||
version "7.17.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57"
|
||||
integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==
|
||||
|
@ -1221,6 +1245,22 @@
|
|||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/traverse@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.10.tgz#37ad97d1cb00efa869b91dd5d1950f8a6cf0cb08"
|
||||
integrity sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/generator" "^7.18.10"
|
||||
"@babel/helper-environment-visitor" "^7.18.9"
|
||||
"@babel/helper-function-name" "^7.18.9"
|
||||
"@babel/helper-hoist-variables" "^7.18.6"
|
||||
"@babel/helper-split-export-declaration" "^7.18.6"
|
||||
"@babel/parser" "^7.18.10"
|
||||
"@babel/types" "^7.18.10"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/traverse@^7.18.6", "@babel/traverse@^7.18.8":
|
||||
version "7.18.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.8.tgz#f095e62ab46abf1da35e5a2011f43aee72d8d5b0"
|
||||
|
@ -1269,6 +1309,15 @@
|
|||
"@babel/helper-validator-identifier" "^7.16.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.18.10":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6"
|
||||
integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.18.10"
|
||||
"@babel/helper-validator-identifier" "^7.18.6"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.18.6", "@babel/types@^7.18.7", "@babel/types@^7.18.8":
|
||||
version "7.18.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.8.tgz#c5af199951bf41ba4a6a9a6d0d8ad722b30cd42f"
|
||||
|
@ -2408,29 +2457,29 @@ babel-plugin-lodash@3.3.4:
|
|||
lodash "^4.17.10"
|
||||
require-package-name "^2.0.1"
|
||||
|
||||
babel-plugin-polyfill-corejs2@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5"
|
||||
integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==
|
||||
babel-plugin-polyfill-corejs2@^0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz#e4c31d4c89b56f3cf85b92558954c66b54bd972d"
|
||||
integrity sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.13.11"
|
||||
"@babel/helper-define-polyfill-provider" "^0.3.1"
|
||||
"@babel/compat-data" "^7.17.7"
|
||||
"@babel/helper-define-polyfill-provider" "^0.3.2"
|
||||
semver "^6.1.1"
|
||||
|
||||
babel-plugin-polyfill-corejs3@^0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72"
|
||||
integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==
|
||||
babel-plugin-polyfill-corejs3@^0.5.3:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz#d7e09c9a899079d71a8b670c6181af56ec19c5c7"
|
||||
integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==
|
||||
dependencies:
|
||||
"@babel/helper-define-polyfill-provider" "^0.3.1"
|
||||
"@babel/helper-define-polyfill-provider" "^0.3.2"
|
||||
core-js-compat "^3.21.0"
|
||||
|
||||
babel-plugin-polyfill-regenerator@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990"
|
||||
integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==
|
||||
babel-plugin-polyfill-regenerator@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz#8f51809b6d5883e07e71548d75966ff7635527fe"
|
||||
integrity sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==
|
||||
dependencies:
|
||||
"@babel/helper-define-polyfill-provider" "^0.3.1"
|
||||
"@babel/helper-define-polyfill-provider" "^0.3.2"
|
||||
|
||||
babel-register@^6.26.0:
|
||||
version "6.26.0"
|
||||
|
@ -2704,7 +2753,7 @@ browserslist@^4.12.0:
|
|||
escalade "^3.0.1"
|
||||
node-releases "^1.1.58"
|
||||
|
||||
browserslist@^4.17.5, browserslist@^4.19.1:
|
||||
browserslist@^4.19.1:
|
||||
version "4.20.2"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88"
|
||||
integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==
|
||||
|
|
Loading…
Add table
Reference in a new issue