refactor list search #27

Merged
floatingghost merged 2 commits from list-searcher into develop 2022-07-05 13:42:18 +00:00
9 changed files with 144 additions and 91 deletions

View file

@ -1,5 +1,6 @@
import { mapState, mapGetters } from 'vuex'
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import ListUserSearch from '../list_user_search/list_user_search.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
@ -15,15 +16,14 @@ library.add(
const ListNew = {
components: {
BasicUserCard,
UserAvatar
UserAvatar,
ListUserSearch
},
data () {
return {
title: '',
userIds: [],
selectedUserIds: [],
loading: false,
query: ''
selectedUserIds: []
}
},
created () {
@ -47,13 +47,6 @@ const ListNew = {
selectedUsers () {
return this.selectedUserIds.map(userId => this.findUser(userId)).filter(user => user)
},
availableUsers () {
if (this.query.length !== 0) {
return this.users
} else {
return this.selectedUsers
}
},
...mapState({
currentUser: state => state.users.currentUser
}),
@ -79,19 +72,8 @@ const ListNew = {
removeUser (userId) {
this.selectedUserIds = this.selectedUserIds.filter(id => id !== userId)
},
search (query) {
if (!query) {
this.loading = false
return
}
this.loading = true
this.userIds = []
this.$store.dispatch('search', { q: query, resolve: true, type: 'accounts', following: true })
.then(data => {
this.loading = false
this.userIds = data.accounts.map(a => a.id)
})
onResults (results) {
this.userIds = results
},
updateList () {
this.$store.dispatch('setList', { id: this.id, title: this.title })

View file

@ -21,23 +21,23 @@
:placeholder="$t('lists.title')"
>
</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="member-list">
<div
v-for="user in availableUsers"
v-for="user in selectedUsers"
:key="user.id"
class="member"
>
<BasicUserCard
:user="user"
:class="isSelected(user) ? 'selected' : ''"
@click.capture.prevent="selectUser(user)"
/>
</div>
</div>
<ListUserSearch @results="onResults" />
<div class="member-list">
<div
v-for="user in users"
:key="user.id"
class="member"
>

View file

@ -1,6 +1,7 @@
import { mapState, mapGetters } from 'vuex'
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
import ListUserSearch from '../list_user_search/list_user_search.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faSearch,
@ -15,15 +16,14 @@ library.add(
const ListNew = {
components: {
BasicUserCard,
UserAvatar
UserAvatar,
ListUserSearch
},
data () {
return {
title: '',
userIds: [],
selectedUserIds: [],
loading: false,
query: ''
selectedUserIds: []
}
},
computed: {
@ -33,13 +33,6 @@ const ListNew = {
selectedUsers () {
return this.selectedUserIds.map(userId => this.findUser(userId))
},
availableUsers () {
if (this.query.length !== 0) {
return this.users
} else {
return this.selectedUsers
}
},
...mapState({
currentUser: state => state.users.currentUser
}),
@ -68,19 +61,8 @@ const ListNew = {
removeUser (userId) {
this.selectedUserIds = this.selectedUserIds.filter(id => id !== userId)
},
search (query) {
if (!query) {
this.loading = false
return
}
this.loading = true
this.userIds = []
this.$store.dispatch('search', { q: query, resolve: true, type: 'accounts', following: true })
.then(data => {
this.loading = false
this.userIds = data.accounts.map(a => a.id)
})
onResults (results) {
this.userIds = results
},
createList () {
// the API has two different endpoints for "creating a list with a name"

View file

@ -21,23 +21,10 @@
:placeholder="$t('lists.title')"
>
</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="member-list">
<div
v-for="user in availableUsers"
v-for="user in selectedUsers"
:key="user.id"
class="member"
>
@ -48,6 +35,21 @@
/>
</div>
</div>
<ListUserSearch
@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"
@ -64,15 +66,6 @@
@import '../../_variables.scss';
.list-new {
.input-wrap {
display: flex;
margin: 0.7em 0.5em 0.7em 0.5em;
input {
width: 100%;
}
}
.search-icon {
margin-right: 0.3em;
}

View 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 ListUserSearch = {
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 ListUserSearch

View 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="./list_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>

View file

@ -970,7 +970,8 @@
"search": "Search users",
"create": "Create",
"save": "Save changes",
"delete": "Delete list"
"delete": "Delete list",
"following_only": "Limit to Following"
},
"file_type": {
"audio": "Audio",

View file

@ -747,8 +747,8 @@ const statuses = {
rootState.api.backendInteractor.fetchRebloggedByUsers({ id })
.then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser }))
},
search (store, { q, resolve, limit, offset, following }) {
return store.rootState.api.backendInteractor.search2({ q, resolve, limit, offset, following })
search (store, { q, resolve, limit, offset, following, type }) {
return store.rootState.api.backendInteractor.search2({ q, resolve, limit, offset, following, type })
.then((data) => {
store.commit('addNewUsers', data.accounts)
store.commit('addNewStatuses', { statuses: data.statuses })

View file

@ -1188,7 +1188,7 @@ const searchUsers = ({ credentials, query }) => {
.then((data) => data.map(parseUser))
}
const search2 = ({ credentials, q, resolve, limit, offset, following }) => {
const search2 = ({ credentials, q, resolve, limit, offset, following, type }) => {
let url = MASTODON_SEARCH_2
let params = []
@ -1212,6 +1212,10 @@ const search2 = ({ credentials, q, resolve, limit, offset, following }) => {
params.push(['following', true])
}
if (type) {
params.push(['type', type])
}
params.push(['with_relationships', true])
let queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')