simplify <List> API and move logic outside of it

This commit is contained in:
Henry Jameson 2026-06-08 05:27:47 +03:00
commit a0d5decc49
15 changed files with 209 additions and 510 deletions

View file

@ -1,7 +1,9 @@
import { isEmpty } from 'lodash'
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import GenericConfirm from 'src/components/confirm_modal/generic_confirm.vue'
import PageList from 'src/components/page_list/page_list.vue'
import List from 'src/components/list/list.vue'
import Popover from 'src/components/popover/popover.vue'
import ProgressButton from 'src/components/progress_button/progress_button.vue'
import Select from 'src/components/select/select.vue'
@ -17,7 +19,6 @@ const UsersTab = {
},
data() {
return {
init: false,
filtersOrigin: 'local',
filtersActivity: 'all',
filtersPrivileges: 'all',
@ -28,6 +29,11 @@ const UsersTab = {
filtersEmail: '',
expandedUser: null,
loading: false,
error: null,
bottomedOut: false,
users: [],
page: 1,
total: null,
}
},
computed: {
@ -79,26 +85,7 @@ const UsersTab = {
filtersExternal() {
return this.filtersOrigin === 'external'
},
},
components: {
Checkbox,
Select,
BasicUserCard,
PageList,
ProgressButton,
AdminCard,
TabSwitcher,
Popover,
GenericConfirm,
},
methods: {
/**
* fetch a new page of users via admin-api
* @param {object} store
* @param {object} opts
*/
fetchPage(store, opts) {
if (!this.init) return new Promise(() => [])
fetchOptions() {
const filters = {
isAdmin: this.filtersIsAdmin,
isModerator: this.filtersIsModerator,
@ -109,22 +96,51 @@ const UsersTab = {
needApproval: this.filtersNeedApproval,
unconfirmed: this.filtersUnconfirmeUnconfirmed,
}
const nopts = {
...opts,
...{
query: this.filtersQuery,
filters,
name: this.filtersName,
email: this.filtersEmail,
},
return {
query: this.filtersQuery,
name: this.filtersName,
email: this.filtersEmail,
pageSize: 50,
filters,
}
return store.dispatch('fetchAdminUsers', nopts)
},
/**
* reset the userlist explicitly
*/
reset() {
this.$refs.userList.reset()
},
components: {
Checkbox,
Select,
BasicUserCard,
List,
ProgressButton,
AdminCard,
TabSwitcher,
Popover,
GenericConfirm,
},
methods: {
fetchPage() {
if (this.loading) return
this.loading = true
this.error = null
this.$store
.dispatch('fetchAdminUsers', {
...this.fetchOptions,
page: this.page,
})
.then((result) => {
console.log('RESULT', result)
this.loading = false
this.bottomedOut = isEmpty(result.users)
this.page += 1
this.total = result.count
this.users.push(...result.users)
})
.catch((error) => {
this.loading = false
this.error = error
})
},
/**
* show the confirmation box for bulk actions.
@ -147,20 +163,18 @@ const UsersTab = {
u.id !== this.$store.state.users.currentUser.id
) {
const uf = this.$store.getters.findUser(u.id)
console.log('user: ', uf)
this.$store.dispatch(action, this.$store.getters.findUser(u.id))
}
})
this.reset()
},
},
/**
* mark as initialized and reset user list
*/
mounted() {
this.init = true
this.reset()
},
watch: {
fetchOptions () {
this.page = 1
this.users = []
this.fetchPage()
}
}
}
export default UsersTab

View file

@ -1,6 +1,6 @@
.UsersTab {
max-height: 100%;
display: grid;
display: flex;
flex-direction: column;
overflow-y: hidden;

View file

@ -14,7 +14,6 @@
<input
v-model="filtersQuery"
class="input string-input filter-input"
@input="reset()"
>
</label>
<label class="filter">
@ -24,7 +23,6 @@
<input
v-model="filtersName"
class="input string-input filter-input"
@input="reset()"
>
</label>
<label class="filter">
@ -34,7 +32,6 @@
<input
v-model="filtersEmail"
class="input string-input filter-input"
@input="reset()"
>
</label>
<div class="filter">
@ -43,7 +40,6 @@
</div>
<Select
v-model="filtersOrigin"
@update:model-value="reset"
>
<option
value="all"
@ -68,7 +64,6 @@
</div>
<Select
v-model="filtersActivity"
@update:model-value="reset"
>
<option
value="all"
@ -91,10 +86,7 @@
<div class="query-label">
{{ $t('admin_dash.users.labels.privileges') }}
</div>
<Select
v-model="filtersPrivileges"
@update:model-value="reset"
>
<Select v-model="filtersPrivileges">
<option
value="all"
>
@ -118,27 +110,25 @@
</Select>
</div>
<div class="filter">
<Checkbox
@update:model-value="v => {filtersNeedApproval = v; reset();}"
>
<Checkbox v-model="filtersNeedApproval">
{{ $t('admin_dash.users.options.only_unapproved') }}
</Checkbox>
</div>
<div class="filter">
<Checkbox
@update:model-value="v => {filtersUncomfirmed = v; reset();}"
>
<Checkbox v-model="filtersUncomfirmed">
{{ $t('admin_dash.users.options.only_unconfirmed') }}
</Checkbox>
</div>
</div>
<PageList
ref="userList"
:refresh="true"
<List
:get-key="i => i"
:box-only="true"
:page-size="20"
:fetch-page="(store, opts) => fetchPage(store, opts)"
:items="users"
:loading="loading"
:error="error"
:bottomed-out="bottomedOut"
@fetch-requested="fetchPage"
selectable
scrollable
>
<template #header>
<Popover
@ -264,7 +254,7 @@
<template #empty>
<span> no users </span>
</template>
</PageList>
</List>
<GenericConfirm
ref="confirmActivate"
:title="$t('admin_dash.users.actions.confirm_multi.title')"

View file

@ -1,6 +1,5 @@
import { get, map, reject } from 'lodash'
import { get, map, reject, isEmpty } from 'lodash'
import withSubscription from 'src/components/../hocs/with_subscription/with_subscription'
import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
import BlockCard from 'src/components/block_card/block_card.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
@ -18,6 +17,15 @@ const MutesAndBlocks = {
data() {
return {
activeTab: 'profile',
mutesLoading: false,
mutesError: null,
mutesBottomedOut: false,
blocksLoading: false,
blocksError: null,
blocksBottomedOut: false,
domainsLoading: false,
domainsError: null,
domainsBottomedOut: false,
}
},
created() {
@ -41,8 +49,37 @@ const MutesAndBlocks = {
user() {
return this.$store.state.users.currentUser
},
blocks() {
return get(this.$store.state.users.currentUser, 'blockIds', [])
},
mutes() {
return get(this.$store.state.users.currentUser, 'muteIds', [])
},
domains() {
return get(this.$store.state.users.currentUser, 'domainMutes', [])
},
},
methods: {
fetchItems(group) {
if (this[group + 'Loading']) return
const capGroup = group[0].toUpperCase() + group.slice(1)
this[group + 'Loading'] = true
this[group + 'Error'] = null
this.$store
.dispatch('fetch' + capGroup, this.userId)
.then((newEntries) => {
this[group + 'Loading'] = false
this[group + 'BottomedOut'] = isEmpty(newEntries)
return newEntries
})
.catch((error) => {
this[group + 'Loading'] = false
this[group + 'Error'] = error
})
},
importFollows(file) {
return this.$store.state.api.backendInteractor
.importFollows({ file })
@ -74,15 +111,6 @@ const MutesAndBlocks = {
})
.join('\n')
},
getBlocks() {
return get(this.$store.state.users.currentUser, 'blockIds', [])
},
getMutes() {
return get(this.$store.state.users.currentUser, 'muteIds', [])
},
getDomainMutes() {
return get(this.$store.state.users.currentUser, 'domainMutes', [])
},
activateTab(tabName) {
this.activeTab = tabName
},

View file

@ -22,8 +22,11 @@
</div>
<List
:get-key="i => i"
:items-function="getBlocks"
:fetch-function="() => $store.dispatch('fetchBlocks')"
:items="blocks"
:loading="blocksLoading"
:error="blocksError"
:bottomed-out="blocksBottomedOut"
@fetch-requested="fetchItems('blocks')"
scrollable
selectable
>
@ -76,8 +79,11 @@
</div>
<List
:get-key="i => i"
:items-function="getMutes"
:fetch-function="() => $store.dispatch('fetchMutes')"
:items="mutes"
:loading="mutesLoading"
:error="mutesError"
:bottomed-out="mutesBottomedOut"
@fetch-requested="fetchItems('mutes')"
scrollable
selectable
>
@ -130,8 +136,11 @@
</div>
<List
:get-key="i => i"
:items-function="getDomainMutes"
:fetch-function="() => $store.dispatch('fetchDomainMutes')"
:items="domains"
:loading="domainsLoading"
:error="domainsError"
:bottomed-out="domainsBottomedOut"
@fetch-requested="fetchItems('domainMutes')"
scrollable
selectable
>