cleaned up, refactored and implemented new <ModerationTools>

This commit is contained in:
Henry Jameson 2026-06-10 01:58:49 +03:00
commit e56ea2dbeb
23 changed files with 1124 additions and 975 deletions

View file

@ -1,8 +1,7 @@
import { defineAsyncComponent } from 'vue'
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
import { useAdminUsersStore } from 'src/stores/adminUsers.js'
import ModerationTools from 'src/components/moderation_tools/moderation_tools.vue'
const AdminCard = {
props: {
@ -12,23 +11,15 @@ const AdminCard = {
},
components: {
BasicUserCard,
ModerationTools: defineAsyncComponent(
() => import('src/components/moderation_tools/moderation_tools.vue'),
),
ModerationTools,
},
computed: {
user() {
return this.$store.getters.findUser(this.userId)
},
userAdminData() {
return useAdminUsersStore().getUser(this.userId)
},
relationship() {
return this.$store.getters.relationship(this.userId)
},
isLocal() {
return this.user.is_local
},
isAdmin() {
return this.user.rights.admin
},
@ -38,12 +29,6 @@ const AdminCard = {
isActivated() {
return !this.user.deactivated
},
isApproved() {
return this.userAdminData.is_approved
},
isConfirmed() {
return this.userAdminData.is_confirmed
},
},
}

View file

@ -26,7 +26,7 @@
</label>
<label
v-if="isActivated"
class="alert info user-role"
class="alert success user-role"
>
{{ $t('admin_dash.users.indicator.active') }}
</label>
@ -37,14 +37,32 @@
{{ $t('admin_dash.users.indicator.deactivated') }}
</label>
<label
v-if="isConfirmed"
class="alert neutral user-role"
v-if="user.adminData.is_confirmed"
class="alert success user-role"
>
{{ $t('admin_dash.users.indicator.confirmed') }}
</label>
<label
v-if="!user.adminData.is_confirmed"
class="alert warning user-role"
>
{{ $t('admin_dash.users.indicator.unconfirmed') }}
</label>
<label
v-if="user.adminData.is_approved"
class="alert success user-role"
>
{{ $t('admin_dash.users.indicator.approved') }}
</label>
<label
v-if="!user.adminData.is_approved"
class="alert warning user-role"
>
{{ $t('admin_dash.users.indicator.unapproved') }}
</label>
<ModerationTools
class="moderation-menu"
:user="user"
:users="[user]"
/>
</div>
</BasicUserCard>

View file

@ -38,7 +38,7 @@ const FrontendsTab = {
},
created() {
if (this.user.rights.admin) {
this.$store.dispatch('loadFrontendsStuff')
useAdminSettingsStore().loadFrontendsStuff()
}
},
computed: {
@ -77,7 +77,7 @@ const FrontendsTab = {
this.working = false
})
.then(async (response) => {
this.$store.dispatch('loadFrontendsStuff')
useAdminSettingsStore().loadFrontendsStuff()
if (response.error) {
const reason = await response.error.json()
useInterfaceStore().pushGlobalNotice({

View file

@ -4,15 +4,26 @@ 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 List from 'src/components/list/list.vue'
import Popover from 'src/components/popover/popover.vue'
import ModerationTools from 'src/components/moderation_tools/moderation_tools.vue'
import ProgressButton from 'src/components/progress_button/progress_button.vue'
import Select from 'src/components/select/select.vue'
import AdminCard from 'src/components/settings_modal/admin_tabs/admin_card.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import { useAdminUsersStore } from 'src/stores/adminUsers.js'
import { useAdminSettingsStore } from 'src/stores/admin_settings.js'
const UsersTab = {
components: {
Checkbox,
Select,
BasicUserCard,
List,
ProgressButton,
AdminCard,
TabSwitcher,
ModerationTools,
GenericConfirm,
},
provide() {
return {
defaultDraftMode: true,
@ -90,7 +101,7 @@ const UsersTab = {
local: this.filtersLocal,
external: this.filtersExternal,
needApproval: this.filtersNeedApproval,
unconfirmed: this.filtersUnconfirmeUnconfirmed,
unconfirmed: this.filtersUnconfirmed,
}
return {
@ -102,51 +113,15 @@ const UsersTab = {
}
},
},
components: {
Checkbox,
Select,
BasicUserCard,
List,
ProgressButton,
AdminCard,
TabSwitcher,
Popover,
GenericConfirm,
},
methods: {
fetchUsers(page) {
return useAdminUsersStore()
return useAdminSettingsStore()
.fetchAdminUsers({
...this.fetchOptions,
page,
})
.then(({ count, users }) => ({ count, items: users }))
},
/**
* show the confirmation box for bulk actions.
* @param {string} box ref name specified for the confirm component
*/
confirmSelection(box) {
this.$refs[box].show()
this.$refs.dropdown.hidePopover()
},
/**
* called when a bulk action was confirmed
* @param {string} action
*/
selectionConfirmed(action) {
const restricted = []
const s = this.$refs.userList.getSelected()
s.forEach((u) => {
if (
restricted.includes(action) !== false ||
u.id !== this.$store.state.users.currentUser.id
) {
const uf = this.$store.getters.findUser(u.id)
this.$store.dispatch(action, this.$store.getters.findUser(u.id))
}
})
},
},
watch: {
fetchOptions() {

View file

@ -115,7 +115,7 @@
</Checkbox>
</div>
<div class="filter">
<Checkbox v-model="filtersUncomfirmed">
<Checkbox v-model="filtersUnconfirmed">
{{ $t('admin_dash.users.options.only_unconfirmed') }}
</Checkbox>
</div>
@ -123,130 +123,15 @@
<List
ref="usersList"
:fetch-function="fetchUsers"
@select="onSelect"
selectable
scrollable
>
<template #header>
<Popover
ref="dropdown"
trigger="click"
placement="bottom"
>
<template #trigger>
<button
class="button button-default btn"
>
{{ $t('admin_dash.users.actions.title') }}
</button>
</template>
<template #content>
<div class="dropdown-menu">
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmActivate')"
>
{{ $t('admin_dash.users.actions.activate') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmDeactivate')"
>
{{ $t('admin_dash.users.actions.deactivate') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmDelete')"
>
{{ $t('admin_dash.users.actions.delete_user') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmGrantAdmin')"
>
{{ $t('admin_dash.users.actions.grant_admin') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmRevokeAdmin')"
>
{{ $t('admin_dash.users.actions.revoke_admin') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmGrantModerator')"
>
{{ $t('admin_dash.users.actions.grant_moderator') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmRevokeModerator')"
>
{{ $t('admin_dash.users.actions.revoke_moderator') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmApprove')"
>
{{ $t('admin_dash.users.actions.approve') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmConfirm')"
>
{{ $t('admin_dash.users.actions.confirm') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmResendEmail')"
>
{{ $t('admin_dash.users.actions.resend_confirmation_email') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmRequirePasswordChange')"
>
{{ $t('admin_dash.users.actions.require_password_change') }}
</button>
</div>
<div class="menu-item dropdown-item">
<button
class="main-button"
@click="confirmSelection('confirmDisableMFA')"
>
{{ $t('admin_dash.users.actions.disable_mfa') }}
</button>
</div>
</div>
</template>
</Popover>
<template #header="{selected}">
<ModerationTools :users="selected" />
</template>
<template #item="{item}">
<AdminCard
:user-id="item.id"
:confirmed="item.is_confirmed"
:suggested="item.is_suggested"
/>
<AdminCard :user-id="item.id" />
</template>
<template #load>
<span> loading </span>
@ -255,102 +140,6 @@
<span> no users </span>
</template>
</List>
<GenericConfirm
ref="confirmActivate"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.activate')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminActivateUser')"
/>
<GenericConfirm
ref="confirmDeactivate"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.deactivate')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminDeactivateUser')"
/>
<GenericConfirm
ref="confirmDelete"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.delete_user')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminDeleteUser')"
/>
<GenericConfirm
ref="confirmGrantAdmin"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.grant_admin')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminAddUserToAdminGroup')"
/>
<GenericConfirm
ref="confirmRevokeAdmin"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.revoke_admin')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminRemoveUserFromAdminGroup')"
/>
<GenericConfirm
ref="confirmGrantModerator"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.grant_moderator')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminAddUserToModeratorGroup')"
/>
<GenericConfirm
ref="confirmRevokeModerator"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.revoke_moderator')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminRemoveUserFromModeratorGroup')"
/>
<GenericConfirm
ref="confirmApprove"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.approve')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminApproveUser')"
/>
<GenericConfirm
ref="confirmConfirm"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.confirm')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminConfirmUser')"
/>
<GenericConfirm
ref="confirmResendEmail"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.resend_confirmation_email')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminResendConfirmationEmail')"
/>
<GenericConfirm
ref="confirmRequirePasswordChange"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.require_password_change')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminRequirePasswordChange')"
/>
<GenericConfirm
ref="confirmDisableMFA"
:title="$t('admin_dash.users.actions.confirm_multi.title')"
:message="$t('admin_dash.users.actions.confirm_multi.disable_mfa')"
:cancel-text="$t('admin_dash.users.actions.no')"
:confirm-text="$t('admin_dash.users.actions.yes')"
@action="selectionConfirmed('adminDisableMFA')"
/>
</div>
</template>
<script src="./users_tab.js"></script>

View file

@ -1,6 +1,7 @@
import { mapState as mapPiniaState } from 'pinia'
import { mapState } from 'vuex'
import { useAdminSettingsStore } from 'src/stores/admin_settings.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
const SharedComputedObject = () => ({
@ -8,9 +9,11 @@ const SharedComputedObject = () => ({
...mapPiniaState(useMergedConfigStore, {
expertLevel: (store) => store.mergedConfig.expertLevel,
}),
...mapPiniaState(useAdminSettingsStore, {
adminConfig: (store) => store.config,
adminDraft: (store) => store.draft,
}),
...mapState({
adminConfig: (state) => state.adminSettings.config,
adminDraft: (state) => state.adminSettings.draft,
user: (state) => state.users.currentUser,
}),
})