fix mess in pagelist, add more options to customize page lists, fix layout in files

This commit is contained in:
luce 2025-07-29 13:31:11 +02:00
commit 628af77f5b
7 changed files with 217 additions and 149 deletions

View file

@ -1,61 +1,61 @@
import SelectableList from 'src/components/selectable_list/selectable_list.vue' import SelectableList from 'src/components/selectable_list/selectable_list.vue'
const PageList = { const PageList = {
components: { components: {
SelectableList SelectableList
}, },
props: { props: {
box_only: { box_only: {
type: Boolean, type: Boolean,
default: false default: false
}, },
page_size: { page_size: {
type: Number, type: Number,
default: 50 default: 50
}, },
fetch_page: { fetch_page: {
type: Function, type: Function,
default: async () => [] default: async () => []
}, },
single_page: { single_page: {
type: Boolean, type: Boolean,
default: false default: false
}
},
data () {
return {
page_index: 1,
items: [],
can_load_more: true,
is_loading: false
}
},
methods: {
reset () {
this.can_load_more = true
this.page_index = 1
this.items = []
this.is_loading = false
this.load_more() // load one page
},
load_more () {
if (!this.is_loading && this.can_load_more) {
this.is_loading = true
this.fetch_page(this.$store, {
page: this.page_index++,
page_size: this.page_size
}).then(items => {
this.items = [...this.items, ...items]
this.is_loading = false
})
} }
}, },
data () { selected () {
return { return this.$refs.list.selected
page_index: 1, }
items: [], },
can_load_more: true, mounted () {
gliter: 0, this.reset()
} }
},
methods: {
reset () {
this.can_load_more = true
this.page_index = 1
this.items = []
this.load_more() // load one page
},
load_more () {
this.gliter++
const iter = this.gliter
this.fetch_page(this.$store, {
page: this.page_index++,
page_size: this.page_size
}).then((items) => {
// ignore if another request was already dispatched
if (iter == this.gliter) {
this.items = [...this.items, ...items]
}
})
},
selected () {
return this.$refs.list.selected
}
},
mounted () {
this.reset()
}
} }
export default PageList export default PageList

View file

@ -18,6 +18,20 @@
v-bind="slotProps" v-bind="slotProps"
/> />
</template> </template>
<template #load="slotProps">
<slot
v-if="is_loading"
name="load"
v-bind="slotProps"
/>
</template>
<template #empty="slotProps">
<slot
v-if="items.length == 0 && !is_loading"
name="empty"
v-bind="slotProps"
/>
</template>
</SelectableList> </SelectableList>
<div v-if="!single_page"> <div v-if="!single_page">
<button <button
@ -28,7 +42,6 @@
> >
{{ $t('page_list.load_more') }} {{ $t('page_list.load_more') }}
</button> </button>
<p> prev first next </p>
</div> </div>
</div> </div>
</template> </template>

View file

@ -17,67 +17,88 @@
</div> </div>
<div <div
v-else v-else
class="setting-item"
> >
<button <ul class="setting-list">
class="button button-default btn" <li>
type="button" <button
@click="top_level_expanded = false" class="button button-default btn"
> type="button"
{{ $t('admin_dash.users.collapse_user') }} @click="top_level_expanded = false"
</button><br> >
<div v-if="is_local"> {{ $t('admin_dash.users.collapse_user') }}
<Checkbox </button>
:model-value="is_admin" </li>
@update:model-value="v => toggle_admin(v)" <li
v-if="is_local"
> >
{{ $t('admin_dash.users.is_admin') }} <Checkbox
</Checkbox><br> :model-value="is_admin"
<Checkbox @update:model-value="v => toggle_admin(v)"
:model-value="is_moderator" >
@update:model-value="v => toggle_moderator(v)" {{ $t('admin_dash.users.is_admin') }}
</Checkbox>
</li>
<li
v-if="is_local"
>
<Checkbox
:model-value="is_moderator"
@update:model-value="v => toggle_moderator(v)"
>
{{ $t('admin_dash.users.is_moderator') }}
</Checkbox>
</li>
<li
v-if="is_local && !just_confirmed && !is_confirmed"
> >
{{ $t('admin_dash.users.is_moderator') }}
</Checkbox><br>
<div v-if="!just_confirmed && !is_confirmed">
<button <button
class="button button-default btn" class="button button-default btn"
type="button" type="button"
@click="confirm_user()" @click="confirm_user()"
> >
{{ $t('admin_dash.users.is_confirmed') }} {{ $t('admin_dash.users.is_confirmed') }}
</button><br> </button>
</li>
<li
v-if="is_local && !just_confirmed && !is_confirmed"
>
<button <button
class="button button-default btn" class="button button-default btn"
type="button" type="button"
@click="resend_confirmation_email()" @click="resend_confirmation_email()"
> >
{{ $t('admin_dash.users.resend_confirmation_email') }} {{ $t('admin_dash.users.resend_confirmation_email') }}
</button><br> </button>
</div> </li>
<div v-if="!is_approved"> <li
v-if="is_local && !is_approved"
>
<button <button
class="button button-default btn" class="button button-default btn"
type="button" type="button"
@click="toggle_approval(true)" @click="toggle_approval(true)"
> >
{{ $t('admin_dash.users.approve') }} {{ $t('admin_dash.users.approve') }}
</button><br> </button>
</div> </li>
</div> <li>
<Checkbox <Checkbox
:model-value="is_activated" :model-value="is_activated"
@update:model-value="v => toggle_activation(v)" @update:model-value="v => toggle_activation(v)"
> >
{{ $t('admin_dash.users.is_active') }} {{ $t('admin_dash.users.is_active') }}
</Checkbox><br> </Checkbox>
<button </li>
class="button button-default btn" <li>
type="button" <button
@click="delete_user()" class="button button-default btn"
> type="button"
{{ $t('admin_dash.users.delete_user') }} @click="delete_user()"
</button> >
{{ $t('admin_dash.users.delete_user') }}
</button>
</li>
</ul>
</div> </div>
<div v-if="!timeline_expanded"> <div v-if="!timeline_expanded">
<button <button
@ -111,6 +132,12 @@
<template #item="{item}"> <template #item="{item}">
<AdminStatusCard :status_details="item" /> <AdminStatusCard :status_details="item" />
</template> </template>
<template #empty>
<p> {{ $t('admin_dash.users.user_has_no_posts') }} </p>
</template>
<template #load>
<p> {{ $t('admin_dash.users.loading') }} </p>
</template>
</PageList> </PageList>
</div> </div>
<div v-if="!json_expanded"> <div v-if="!json_expanded">

View file

@ -1,6 +1,6 @@
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import Select from 'src/components/select/select.vue' import Select from 'src/components/select/select.vue'
import StatusBody from 'src/components/status_body/status_body.vue' import Status from 'src/components/status/status.vue'
import { parseStatus } from 'src/services/entity_normalizer/entity_normalizer.service.js' import { parseStatus } from 'src/services/entity_normalizer/entity_normalizer.service.js'
const AdminStatusCard = { const AdminStatusCard = {
@ -30,7 +30,7 @@ const AdminStatusCard = {
components: { components: {
Checkbox, Checkbox,
Select, Select,
StatusBody, Status,
}, },
mounted () { mounted () {
this.$store.dispatch('adminChangeStatusScope', { opts: { id: this.status_details.id }}).then(res => parseStatus(res)).then(s => this.status_cache = s) this.$store.dispatch('adminChangeStatusScope', { opts: { id: this.status_details.id }}).then(res => parseStatus(res)).then(s => this.status_cache = s)

View file

@ -1,55 +1,80 @@
<template> <template>
<div class="setting-item"> <div class="setting-item">
<h2> {{ $t('admin_dash.users.title_info') }}: </h2> <h2> {{ $t('admin_dash.users.title_info') }}: </h2>
<span> {{ $t('admin_dash.users.status_id') }}: {{ status_details.id }} </span> <ul
<span> {{ $t('admin_dash.users.created_at') }}: {{ status_details.created_at }} </span> class="setting-list"
<span v-if="typeof(status_details.edited_at) !== 'undefined'"> {{ $t('admin_dash.users.edited_at') }}: {{ status_details.edited_at }} </span> >
<li>
<span> {{ $t('admin_dash.users.status_id') }}: {{ status_details.id }} </span>
</li>
<li>
<span> {{ $t('admin_dash.users.created_at') }}: {{ new Date(status_details.created_at).toLocaleString() }} </span>
</li>
<li>
<span v-if="status_details.edited_at !== null"> {{ $t('admin_dash.users.edited_at') }}: {{ new Date(status_details.edited_at).toLocaleString() }} </span>
</li>
</ul>
<h2> {{ $t('admin_dash.users.title_content') }}: </h2> <h2> {{ $t('admin_dash.users.title_content') }}: </h2>
<div> <ul
<StatusBody class="setting-list"
v-if="typeof(status_cache) !== 'undefined'"
:status="status_cache"
/>
</div>
<button
class="button button-default btn"
type="button"
@click="delete_status(status.id)"
> >
{{ $t('admin_dash.users.delete_status') }} <li>
</button><br> <Status
<Checkbox v-if="typeof(status_cache) !== 'undefined'"
:model-value="is_sensitive" class="Notification"
@update:model-value="v => change_sensitivity(v)" :compact="true"
> :statusoid="status_cache"
{{ $t('admin_dash.users.content_nsfw') }} @interacted="false"
</Checkbox> />
<Select </li>
:model-value="visibility" <li>
@update:model-value="v => change_visibility(v)" <button
> class="button button-default btn"
<option type="button"
value="public" @click="delete_status(status.id)"
> >
{{ $t('admin_dash.users.scope_public') }} {{ $t('admin_dash.users.delete_status') }}
</option> </button>
<option </li>
value="unlisted" <li>
> <Checkbox
{{ $t('admin_dash.users.scope_unlisted') }} :model-value="is_sensitive"
</option> @update:model-value="v => change_sensitivity(v)"
<option >
value="private" {{ $t('admin_dash.users.content_nsfw') }}
> </Checkbox>
{{ $t('admin_dash.users.scope_private') }} </li>
</option> <li>
<option <Select
value="direct" :model-value="visibility"
> @update:model-value="v => change_visibility(v)"
{{ $t('admin_dash.users.scope_direct') }} >
</option> <option
</Select><br> value="public"
<a :href="status_details.url"> {{ $t('admin_dash.users.link_source') }} </a> >
{{ $t('admin_dash.users.scope_public') }}
</option>
<option
value="unlisted"
>
{{ $t('admin_dash.users.scope_unlisted') }}
</option>
<option
value="private"
>
{{ $t('admin_dash.users.scope_private') }}
</option>
<option
value="direct"
>
{{ $t('admin_dash.users.scope_direct') }}
</option>
</Select>
</li>
<li>
<a :href="status_details.url"> {{ $t('admin_dash.users.link_source') }} </a>
</li>
</ul>
<div v-if="!json_expanded"> <div v-if="!json_expanded">
<button <button
class="button button-default btn" class="button button-default btn"

View file

@ -15,9 +15,8 @@ const UsersTab = {
}, },
data() { data() {
return { return {
/* filters must match the filter options below initially, or the ui is gonna have a computer moment init: false, /* avoid fetching before our filters got initialized */
* no, i won't fix this /* adjust filters_... options here, mounted() will adjust the other flags accordingly */
* */
filters_origin: 'local', filters_origin: 'local',
filters_activity: 'all', filters_activity: 'all',
filters_permission: 'all', filters_permission: 'all',
@ -104,6 +103,7 @@ const UsersTab = {
this.reset() this.reset()
}, },
fetch_page (store, opts) { fetch_page (store, opts) {
if(!this.init) return new Promise(() => [])
const users = store.dispatch('fetchAdminUsers', { ...opts, ...{ const users = store.dispatch('fetchAdminUsers', { ...opts, ...{
query: this.filters_query, query: this.filters_query,
filters: this.filters, filters: this.filters,
@ -134,6 +134,8 @@ const UsersTab = {
this.update_origin(this.filters_origin) this.update_origin(this.filters_origin)
this.update_activity(this.filters_activity) this.update_activity(this.filters_activity)
this.update_permission(this.filters_permission) this.update_permission(this.filters_permission)
this.init = true
this.reset()
} }
} }

View file

@ -1187,7 +1187,8 @@
"title_database": "Database", "title_database": "Database",
"title_details": "Details", "title_details": "Details",
"title_filter_user_search": "Filter User Search", "title_filter_user_search": "Filter User Search",
"title_users": "Users" "title_users": "Users",
"user_has_no_posts": "User has no posts"
}, },
"limits": { "limits": {
"arbitrary_limits": "Arbitrary limits", "arbitrary_limits": "Arbitrary limits",