This commit is contained in:
Henry Jameson 2026-06-08 20:31:42 +03:00
commit 7d3f46c529
13 changed files with 137 additions and 828 deletions

View file

@ -57,7 +57,7 @@ const List = {
return new Set(this.finalItems.map(this.getKey)) return new Set(this.finalItems.map(this.getKey))
}, },
filteredSelected() { filteredSelected() {
return [ ...this.allKeys.values().filter((key) => this.selected.has(key))] return [...this.allKeys.values().filter((key) => this.selected.has(key))]
}, },
allSelected() { allSelected() {
return this.selected.size === this.finalItems.length return this.selected.size === this.finalItems.length
@ -70,7 +70,7 @@ const List = {
}, },
finalItems() { finalItems() {
return this.externalItems || this.items return this.externalItems || this.items
} },
}, },
created() { created() {
window.addEventListener('scroll', this.scrollLoad) window.addEventListener('scroll', this.scrollLoad)

View file

@ -1,5 +1,5 @@
<template> <template>
<basic-user-card :user="user"> <BasicUserCard :user="user">
<div class="mute-card-content-container"> <div class="mute-card-content-container">
<span <span
v-if="muted && muteExpiryAvailable" v-if="muted && muteExpiryAvailable"
@ -30,7 +30,7 @@
:is-mute="true" :is-mute="true"
/> />
</teleport> </teleport>
</basic-user-card> </BasicUserCard>
</template> </template>
<script src="./mute_card.js"></script> <script src="./mute_card.js"></script>

View file

@ -1,291 +1,49 @@
import Checkbox from 'src/components/checkbox/checkbox.vue' import { defineAsyncComponent } from 'vue'
import GenericConfirm from 'src/components/confirm_modal/generic_confirm.vue'
import TextConfirm from 'src/components/confirm_modal/text_confirm.vue' import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
import Modal from 'src/components/modal/modal.vue'
import List from 'src/components/list/list.vue' import { useAdminUsersStore } from 'src/stores/adminUsers.js'
import Popover from 'src/components/popover/popover.vue'
import Select from 'src/components/select/select.vue'
import AdminStatusCard from 'src/components/settings_modal/admin_tabs/admin_status_card.vue'
import BasicUserCard from '../../basic_user_card/basic_user_card.vue'
const AdminCard = { const AdminCard = {
props: { props: {
/** userId: {
* minimal user info type: String
* @type {import('vue').PropType<{
* id: string,
* _original: {
* is_approved: boolean;
* is_confirmed: boolean;
* };
* }>}
*/
userDetails: {
type: Object,
required: true,
/**
* @param {any} u
* @returns {u is { id: string; _original: { is_approved; is_confirmed: boolean; } } }
*/
validator(u) {
return (
typeof u.id === 'string' &&
typeof u._original === 'object' &&
typeof u._original.is_approved === 'boolean' &&
typeof u._original.is_confirmed === 'boolean'
)
},
},
},
data() {
return {
progress: false,
detailsExpanded: false,
topLevelExpanded: false, // REMOVE
jsonExpanded: false,
timelineExpanded: false,
justApproved: false,
justConfirmed: false,
justDeleted: false,
showDirect: false,
showReblogs: false,
timelineSorting: 'des',
}
},
computed: {
/**
* checks if the user is defined
* @returns {boolean}
*/
isLoaded() {
return typeof this.user !== 'undefined'
},
/**
* @returns {object} user info
*/
user() {
return this.$store.getters.findUser(this.userDetails.id)
},
/**
* @returns {object} user relationship
*/
relationship() {
return this.$store.getters.relationship(this.userDetails.id)
},
/**
* @returns {boolean} is user local
*/
isLocal() {
const u = this.$store.getters.findUser(this.userDetails.id)
if (typeof u !== 'undefined') {
return u.is_local === true
}
return false
},
/**
* @returns {boolean} is user admin
*/
isAdmin() {
const u = this.$store.getters.findUser(this.userDetails.id)
if (typeof u !== 'undefined') {
return u.rights.admin === true
}
return false
},
/**
* @returns {boolean} is user moderator
*/
isModerator() {
const u = this.$store.getters.findUser(this.userDetails.id)
if (typeof u !== 'undefined') {
return u.rights.moderator === true
}
return false
},
/**
* @returns {boolean} is user active
*/
isActivated() {
const u = this.$store.getters.findUser(this.userDetails.id)
if (typeof u !== 'undefined') {
return u.deactivated === false
}
return false
},
/**
* @returns {boolean} has this user been confirmed
*/
isConfirmed() {
const u = this.$store.getters.findUser(this.userDetails.id)
return u._original.is_confirmed === true || this.justConfirmed === true
},
/**
* @returns {boolean} has this user been approved
*/
isApproved() {
return (
this.userDetails._original.is_approved === true ||
this.justApproved === true
)
}, },
}, },
components: { components: {
BasicUserCard, BasicUserCard,
Checkbox, ModerationTools: defineAsyncComponent(
List, () => import('src/components/moderation_tools/moderation_tools.vue'),
AdminStatusCard, ),
Modal,
Popover,
GenericConfirm,
Select,
TextConfirm,
}, },
methods: { computed: {
/** user() {
* @param {boolean} v set admin status return this.$store.getters.findUser(this.userId)
*/
setAdmin(v) {
const u = this.$store.getters.findUser(this.userDetails.id)
if (v === true) {
this.$store.dispatch('adminAddUserToAdminGroup', u)
} else {
this.$store.dispatch('adminRemoveUserFromAdminGroup', u)
}
}, },
/** userAdminData() {
* @param {boolean} v set moderator status return useAdminUsersStore().getUser(this.userId)
*/
setModerator(v) {
const u = this.$store.getters.findUser(this.userDetails.id)
if (v === true) {
this.$store.dispatch('adminAddUserToModeratorGroup', u)
} else {
this.$store.dispatch('adminRemoveUserFromModeratorGroup', u)
}
}, },
/** relationship() {
* @param {boolean} v set activation status return this.$store.getters.relationship(this.userId)
*/
setActivation(v) {
const u = this.$store.getters.findUser(this.userDetails.id)
if (v === true) {
this.$store.dispatch('adminActivateUser', u)
} else {
this.$store.dispatch('adminDeactivateUser', u)
}
}, },
/** isLocal() {
* confirm this user return this.user.is_local
*/
confirmUser() {
const u = this.$store.getters.findUser(this.userDetails.id)
this.$store.dispatch('adminConfirmUser', u)
this.just_confirmed = true
}, },
/** isAdmin() {
* try resending the confirmation email return this.user.rights.admin
*/
resendConfirmationEmail() {
const u = this.$store.getters.findUser(this.userDetails.id)
this.$store.dispatch('adminResendConfirmationEmail', u)
}, },
/** isModerator() {
* approve this user return this.user.rights.moderator
*/
approveUser() {
const u = this.$store.getters.findUser(this.userDetails.id)
this.$store.dispatch('adminApproveUser', u)
}, },
/** isActivated() {
* update user info from server return !this.user.deactivated
*/
forceUpdateUser() {
this.$store.dispatch('fetchUser', this.userDetails.id)
}, },
/** isApproved() {
* delete selected statuses return this.userAdminData.is_approved
*/
deleteSelection() {
const l = this.$refs.timelineList
const s = l.getSelected()
s.forEach((p) => this.$store.dispatch('deleteStatus', p))
l.reset()
},
/**
* delete this user. keep in mind that user deletion is not intuitive in pleroma backend.
* it actually deletes all content of a user. the user itself will keep showing up in search results.
*/
deleteUser() {
if (!this.justDeleted) {
const u = this.$store.getters.findUser(this.userDetails.id)
this.$store.dispatch('adminDeleteUser', u)
this.justDeleted = true
}
},
/**
* @param {string} text name of tag to be added to user
*/
addUserTag(text) {
const u = this.$store.getters.findUser(this.userDetails.id)
this.$store
.dispatch('adminTagUser', { user: u, tag: text })
.then(() => this.$store.dispatch('fetchUser', this.userDetails.id))
},
/**
* @param {string} text name of tag to be removed from user
*/
removeUserTag(text) {
const u = this.$store.getters.findUser(this.userDetails.id)
this.$store
.dispatch('adminUntagUser', { user: u, tag: text })
.then(() => this.$store.dispatch('fetchUser', this.userDetails.id))
},
/**
* @param {object} store
* @param {object} opts
* @returns {Promise<Array<object>>} statuses
*/
async fetchStatuses(store, opts) {
const u = this.$store.getters.findUser(this.userDetails.id)
const res = store.dispatch('adminListStatuses', {
user: u,
opts: {
pageSize: opts.pageSize,
godmode: this.showDirect,
withReblogs: this.showReblogs,
},
})
return res.then((r) => {
const a = r.activities
console.log(this.timelineSorting)
if (this.timelineSorting === 'des') {
return [...a].sort(
(a, b) => new Date(b.created_at) - new Date(a.created_at),
)
} else if (this.timelineSorting === 'asc') {
return [...a].sort(
(a, b) => new Date(a.created_at) - new Date(b.created_at),
)
} else return []
})
},
confirmAction(box) {
this.$refs[box].show()
this.$refs.dropdownuser.hidePopover()
},
userActionConfirmed(action) {
this.$store.dispatch(
action,
this.$store.getters.findUser(this.userDetails.id),
)
},
statusActionConfirmed(action, opts) {
const s = this.$refs.statusList.getSelected()
s.forEach((p) => {
this.$store.dispatch(action, { id: p.id, ...(opts || {}) })
})
this.reset()
}, },
isConfirmed() {
return this.userAdminData.is_confirmed
}
}, },
} }

View file

@ -1,19 +1,9 @@
.inline-layout { .AdminCard {
display: flex;
align-items: center;
width: 100%; width: 100%;
gap: 8px;
}
.alert { .right-side {
text-shadow: none; align-items: baseline;
} justify-content: end;
display: flex;
.user-role { }
display: inline-block;
vertical-align: baseline;
}
.modalfix::before {
opacity: 1.0;
} }

View file

@ -1,528 +1,56 @@
<template> <template>
<div v-if="!isLoaded"> <template v-if="!user">
<FAIcon <FAIcon
icon="circle-notch" icon="circle-notch"
spin spin
size="lg" size="lg"
/> />
</div> </template>
<div v-else> <template v-else>
<div class="inline-layout"> <BasicUserCard
<BasicUserCard :user="user" /> class="AdminCard"
<label :user="user"
v-if="isAdmin"
class="alert neutral user-role"
>
{{ $t('admin_dash.users.indicator.admin') }}
</label>
<label
v-if="isModerator"
class="alert neutral user-role"
>
{{ $t('admin_dash.users.indicator.moderator') }}
</label>
<label
v-if="isActivated"
class="alert info user-role"
>
{{ $t('admin_dash.users.indicator.active') }}
</label>
<label
v-if="!isActivated"
class="alert error user-role"
>
{{ $t('admin_dash.users.indicator.deactivated') }}
</label>
<label
v-if="isConfirmed"
class="alert neutral user-role"
>
{{ $t('admin_dash.users.indicator.confirmed') }}
</label>
<button
class="button button-default btn"
type="button"
@click="detailsExpanded = true"
>
{{ $t('admin_dash.users.details.button') }}
</button>
<Popover
ref="dropdownuser"
trigger="click"
placement="top"
>
<template #trigger>
<button
class="button button-default btn"
>
{{ $t('admin_dash.users.actions.title') }}
</button>
</template>
<template #content>
<div
v-if="!isActivated"
class="dropdown-menu"
>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmActivate')"
>
{{ $t('admin_dash.users.activate') }}
</button>
</div>
</div>
<div
v-if="isActivated"
class="dropdown-menu"
>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmDeactivate')"
>
{{ $t('admin_dash.users.actions.deactivate') }}
</button>
</div>
</div>
<div class="dropdown-menu">
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmDeleteUser')"
>
{{ $t('admin_dash.users.actions.delete_user') }}
</button>
</div>
</div>
<div
v-if="!isAdmin"
class="dropdown-menu"
>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmGrantAdmin')"
>
{{ $t('admin_dash.users.actions.grant_admin') }}
</button>
</div>
</div>
<div
v-if="isAdmin"
class="dropdown-menu"
>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmRevokeAdmin')"
>
{{ $t('admin_dash.users.actions.revoke_admin') }}
</button>
</div>
</div>
<div
v-if="!isModerator"
class="dropdown-menu"
>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmGrantModerator')"
>
{{ $t('admin_dash.users.actions.grant_moderator') }}
</button>
</div>
</div>
<div
v-if="isModerator"
class="dropdown-menu"
>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmRevokeModerator')"
>
{{ $t('admin_dash.users.actions.revoke_moderator') }}
</button>
</div>
</div>
<div
v-if="isApproved"
class="dropdown-menu"
>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmApprove')"
>
{{ $t('admin_dash.users.actions.approve') }}
</button>
</div>
</div>
<div
v-if="isConfirmed"
class="dropdown-menu"
>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmConfirm')"
>
{{ $t('admin_dash.users.actions.confirm') }}
</button>
</div>
</div>
<div class="dropdown-menu">
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmResendConfirmationEmail')"
>
{{ $t('admin_dash.users.actions.resend_confirmation_email') }}
</button>
</div>
</div>
<div class="dropdown-menu">
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmRequirePasswordChange')"
>
{{ $t('admin_dash.users.actions.require_password_change') }}
</button>
</div>
</div>
<div class="dropdown-menu">
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmDisableMFA')"
>
{{ $t('admin_dash.users.actions.disable_mfa') }}
</button>
</div>
</div>
</template>
</Popover>
</div>
<div
v-if="detailsExpanded"
> >
<Modal <div class="right-side">
class="settings-modal" <label
:no-background="false" v-if="isAdmin"
@backdrop-clicked="() => { detailsExpanded = false }" class="alert neutral user-role"
> >
<div class="settings-modal-panel panel"> {{ $t('admin_dash.users.indicator.admin') }}
<div class="panel-heading"> </label>
<h1 class="title"> <label
{{ $t('admin_dash.users.details.title') }} v-if="isModerator"
</h1> class="alert neutral user-role"
<button >
class="btn button-default" {{ $t('admin_dash.users.indicator.moderator') }}
:title="$t('general.close')" </label>
@click="() => { detailsExpanded = false }" <label
> v-if="isActivated"
<FAIcon class="alert info user-role"
icon="times" >
fixed-width {{ $t('admin_dash.users.indicator.active') }}
/> </label>
</button> <label
</div> v-if="!isActivated"
<div class="alert error user-role"
class="panel-body" >
style="overflow-y: auto;" {{ $t('admin_dash.users.indicator.deactivated') }}
> </label>
<h2 class="title"> <label
{{ $t('admin_dash.users.details.overview') }} v-if="isConfirmed"
</h2> class="alert neutral user-role"
<ul >
class="setting-list" {{ $t('admin_dash.users.indicator.confirmed') }}
style="columns: 2;" </label>
> <ModerationTools
<li> class="moderation-menu"
{{ $t('admin_dash.users.details.id') }} :user="user"
</li> />
<li> </div>
{{ $t('admin_dash.users.details.actor_type') }} </BasicUserCard>
</li> </template>
<li>
{{ $t('admin_dash.users.details.roles') }}
</li>
<li>
{{ $t('admin_dash.users.details.account_type') }}
</li>
<li>
{{ $t('admin_dash.users.details.status') }}
</li>
<li>
{{ user.id }}
</li>
<li>
{{ $t('admin_dash.users.details.actor_types.' + user.actor_type.toLowerCase()) }}
</li>
<li>
<span v-if="user.rights.admin === true"> {{ $t('admin_dash.users.details.admin') }} </span>
<span v-if="user.rights.admin === true && user.rights.moderator === true"> ,&nbsp; </span>
<span v-if="user.rights.moderator === true"> {{ $t('admin_dash.users.details.moderator') }} </span>
</li>
<li>
<span v-if="user.is_local"> {{ $t('admin_dash.users.details.local') }} </span>
<span v-else> {{ $t('admin_dash.users.details.remote') }} </span>
</li>
<li>
<span v-if="user.deactivated === false"> {{ $t('admin_dash.users.details.active') }} </span>
<span v-else> {{ $t('admin_dash.users.details.inactive') }} </span>
</li>
</ul>
<h2 class="title">
{{ $t('admin_dash.users.details.tags') }}
</h2>
<ul class="setting-list">
<li
v-for="tag in user.tags"
:key="tag"
>
{{ tag }}
<button
class="button button-default btn"
@click="removeUserTag(tag)"
>
<FAIcon
icon="minus"
size="lg"
/>
</button>
</li>
</ul>
<button
class="button button-default btn"
@click="$refs.addTextBox.show()"
>
{{ $t('admin_dash.users.tags.add_new') }}
<FAIcon
icon="plus"
size="lg"
/>
</button>
<PageList
ref="timelineList"
:refresh="true"
:get-key="i => i"
:box-only="true"
:page-size="20"
:single-page="true"
:fetch-page="(store, opts) => fetchStatuses(store, opts)"
>
<template #header>
<Checkbox
v-model="showDirect"
@update:model-value="() => $refs.timelineList.reset()"
>
{{ $t('admin_dash.users.filters.show_direct') }}
</Checkbox>
<Checkbox
v-model="showReblogs"
@update:model-value="() => $refs.timelineList.reset()"
>
{{ $t('admin_dash.users.filters.show_reblogs') }}
</Checkbox>
<Select
v-model="timelineSorting"
@update:model-value="() => $refs.timelineList.reset()"
>
<option value="asc">
{{ $t('admin_dash.users.filters.ascending') }}
</option>
<option value="des">
{{ $t('admin_dash.users.filters.descending') }}
</option>
</Select>
<Popover
ref="dropdownstatus"
trigger="click"
placement="top"
>
<template #trigger>
<button
class="button button-default btn"
>
{{ $t('admin_dash.users.actions.title') }}
</button>
</template>
<p> wrap </p>
<template #content>
<div class="dropdown-menu">
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmAction('confirmDeleteStatus')"
>
{{ $t('admin_dash.users.delete_status') }}
</button>
</div>
<p> set sensitive </p>
<p> unset sensitive </p>
<p> make public </p>
<p> make unlisted </p>
<p> make private </p>
<p> make direct </p>
</div>
</template>
</Popover>
</template>
<template #item="{item}">
<AdminStatusCard
:status-details="item"
style="width: 100%"
/>
</template>
<template #empty>
<p> {{ $t('admin_dash.users.user_has_no_posts') }} </p>
</template>
<template #load>
<FAIcon
icon="circle-notch"
spin
size="lg"
/>
</template>
</PageList>
</div>
</div>
</Modal>
</div>
</div>
<GenericConfirm
ref="confirmActivate"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.activate')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminActivateUser')"
/>
<GenericConfirm
ref="confirmDeactivate"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.deactivate')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminDeactivateUser')"
/>
<GenericConfirm
ref="confirmDeleteUser"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.delete_user')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminDeleteUser')"
/>
<GenericConfirm
ref="confirmGrantAdmin"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.grant_admin')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminAddUserToAdminGroup')"
/>
<GenericConfirm
ref="confirmRevokeAdmin"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.revoke_admin')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminRemoveUserFromAdminGroup')"
/>
<GenericConfirm
ref="confirmGrantModerator"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.grant_moderator')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminAddUserToModeratorGroup')"
/>
<GenericConfirm
ref="confirmRevokeModerator"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.revoke_moderator')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminRemoveUserFromModeratorGroup')"
/>
<GenericConfirm
ref="confirmApprove"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.approve')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminApproveUser')"
/>
<GenericConfirm
ref="confirmConfirm"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.confirm')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminConfirmUser')"
/>
<GenericConfirm
ref="confirmResendConfirmationEmail"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.resend_confirmation_email')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminResendConfirmationEmail')"
/>
<GenericConfirm
ref="confirmRequirePasswordChange"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.require_password_change')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminRequirePasswordChange')"
/>
<GenericConfirm
ref="confirmDisableMFA"
style="z-index: 10000;"
:title="$t('admin_dash.users.actions.confirm_single.title')"
:message="$t('admin_dash.users.actions.confirm_single.disable_mfa')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="userActionConfirmed('adminDisableMFA')"
/>
<TextConfirm
ref="addTextBox"
style="z-index: 10001;"
:title="$t('admin_dash.users.tags.add_new')"
:message="$t('admin_dash.users.tags.new_title')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="addUserTag"
/>
</template> </template>
<script src="./admin_card.js"></script> <script src="./admin_card.js"></script>
<style lang="scss" src="./admin_card.scss"></style>
<style lang="scss" src="../settings_modal.scss"></style>
<!--<style lang="scss">
.admin-card-content-container {
margin-top: 0.5em;
text-align: right;
button { <style lang="scss" src="./admin_card.scss"></style>
width: 10em;
}
}
</style>-->

View file

@ -10,6 +10,8 @@ import Select from 'src/components/select/select.vue'
import AdminCard from 'src/components/settings_modal/admin_tabs/admin_card.vue' import AdminCard from 'src/components/settings_modal/admin_tabs/admin_card.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import { useAdminUsersStore } from 'src/stores/adminUsers.js'
const UsersTab = { const UsersTab = {
provide() { provide() {
return { return {
@ -113,9 +115,7 @@ const UsersTab = {
}, },
methods: { methods: {
fetchUsers(page) { fetchUsers(page) {
console.log(page) return useAdminUsersStore().fetchAdminUsers({
return this.$store
.dispatch('fetchAdminUsers', {
...this.fetchOptions, ...this.fetchOptions,
page, page,
}) })
@ -148,10 +148,10 @@ const UsersTab = {
}, },
}, },
watch: { watch: {
fetchOptions () { fetchOptions() {
this.$refs.usersList.reset() this.$refs.usersList.reset()
} },
} },
} }
export default UsersTab export default UsersTab

View file

@ -242,7 +242,11 @@
</Popover> </Popover>
</template> </template>
<template #item="{item}"> <template #item="{item}">
<AdminCard :user-details="item" /> <AdminCard
:user-id="item.id"
:confirmed="item.is_confirmed"
:suggested="item.is_suggested"
/>
</template> </template>
<template #load> <template #load>
<span> loading </span> <span> loading </span>

View file

@ -1,4 +1,4 @@
import { get, map, reject, isEmpty } from 'lodash' import { get, isEmpty, map, reject } from 'lodash'
import Autosuggest from 'src/components/autosuggest/autosuggest.vue' import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
import BlockCard from 'src/components/block_card/block_card.vue' import BlockCard from 'src/components/block_card/block_card.vue'

View file

@ -27,7 +27,8 @@
width: 10em; width: 10em;
} }
.blocks, .mutes { .blocks,
.mutes {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100%; min-height: 100%;

View file

@ -103,10 +103,10 @@ const UserProfile = {
this.footerRef = el this.footerRef = el
}, },
fetchUsers(group) { fetchUsers(group) {
return () => this return () =>
.$store this.$store
.dispatch('fetch' + group, this.userId) .dispatch('fetch' + group, this.userId)
.then((result) => ({ items: result })) .then((result) => ({ items: result }))
}, },
load(userNameOrId) { load(userNameOrId) {
const startFetchingTimeline = (timeline, userId) => { const startFetchingTimeline = (timeline, userId) => {

View file

@ -151,9 +151,9 @@ const adminSettingsStorage = {
adminApproveUser(store, user) { adminApproveUser(store, user) {
return store.rootState.api.backendInteractor.adminApproveUser({ user }) return store.rootState.api.backendInteractor.adminApproveUser({ user })
}, },
adminListStatuses(store, { user, opts }) { adminListStatuses(store, { userId, opts }) {
return store.rootState.api.backendInteractor.adminListStatuses({ return store.rootState.api.backendInteractor.adminListStatuses({
user, userId,
opts, opts,
}) })
}, },

View file

@ -1740,17 +1740,19 @@ const adminApproveUser = ({ user: { screen_name: nickname }, credentials }) => {
} }
const adminListStatuses = ({ const adminListStatuses = ({
user: { id }, userId,
opts: { pageSize, godmode, withReblogs }, pageSize = 20,
godmode,
withReblogs,
credentials, credentials,
}) => { }) => {
const url = PLEROMA_ADMIN_LIST_STATUSES_URL( const url = PLEROMA_ADMIN_LIST_STATUSES_URL(
id, userId,
pageSize, pageSize,
godmode, godmode,
withReblogs, withReblogs,
) )
return promisedRequest({ url: url, credentials, method: 'GET' }) return promisedRequest({ url, credentials, method: 'GET' })
} }
const adminChangeStatusScope = ({ const adminChangeStatusScope = ({

26
src/stores/adminUsers.js Normal file
View file

@ -0,0 +1,26 @@
import { defineStore } from 'pinia'
export const useAdminUsersStore = defineStore('adminUsers', {
state: () => ({
users: new Map()
}),
getters: {
getUser(state) {
return (id) => state.users.get(id)
},
},
actions: {
async fetchAdminUsers(opts) {
const data = await window.vuex.state.api.backendInteractor.adminListUsers({
opts,
})
data.users.forEach((user) => {
window.vuex.dispatch('fetchUserIfMissing', user.id),
this.users.set(user.id, user)
})
return data
},
},
})