review pass 1

This commit is contained in:
Henry Jameson 2026-06-10 19:30:08 +03:00
commit d94cac6376
25 changed files with 56 additions and 292 deletions

View file

@ -411,6 +411,14 @@ nav {
button:not(.button-default) { button:not(.button-default) {
color: var(--text); color: var(--text);
font-size: 100%; font-size: 100%;
text-align: initial;
padding: 0;
background: none;
border: none;
outline: none;
display: inline;
font-family: inherit;
line-height: unset;
} }
&.disabled { &.disabled {
@ -436,22 +444,6 @@ nav {
--__line-height: 1.5em; --__line-height: 1.5em;
--__horizontal-gap: 0.75em; --__horizontal-gap: 0.75em;
--__vertical-gap: 0.5em; --__vertical-gap: 0.5em;
&.-non-interactive {
cursor: auto;
}
> a,
> button:not(.button-default) {
text-align: initial;
padding: 0;
background: none;
border: none;
outline: none;
display: inline;
font-family: inherit;
line-height: unset;
}
} }
.button-unstyled { .button-unstyled {

View file

@ -1,5 +1,5 @@
<template> <template>
<basic-user-card :user="user"> <BasicUserCard :user="user">
<div class="block-card-content-container"> <div class="block-card-content-container">
<span <span
v-if="blocked && blockExpiryAvailable" v-if="blocked && blockExpiryAvailable"
@ -30,7 +30,7 @@
:is-mute="false" :is-mute="false"
/> />
</teleport> </teleport>
</basic-user-card> </BasicUserCard>
</template> </template>
<script src="./block_card.js"></script> <script src="./block_card.js"></script>

View file

@ -17,7 +17,7 @@ const Interactions = {
allowFollowingMove: allowFollowingMove:
this.$store.state.users.currentUser.allow_following_move, this.$store.state.users.currentUser.allow_following_move,
filterMode: tabModeDict.mentions, filterMode: tabModeDict.mentions,
canSeeReports: this.$store.state.users.currentUser.has.has( canSeeReports: this.$store.state.users.currentUser.privileges.has(
'reports_manage_reports', 'reports_manage_reports',
), ),
} }

View file

@ -1,6 +1,7 @@
<template> <template>
<div <div
class="List" class="List"
role="list"
:class="{ '-scrollable': scrollable }" :class="{ '-scrollable': scrollable }"
> >
<div <div

View file

@ -50,7 +50,7 @@
</div> </div>
<tab-switcher <tab-switcher
class="list-member-management" class="list-member-management"
:scrollable-tabs="true" :scrollable-tabs
> >
<div <div
v-if="id || addedUserIds.size > 0" v-if="id || addedUserIds.size > 0"

View file

@ -215,22 +215,17 @@ const ModerationTools = {
return () => this.setTag(`${group}:${name}`, noTag) return () => this.setTag(`${group}:${name}`, noTag)
case 'action': { case 'action': {
switch (name) { switch (name) {
case 'delete': { case 'delete':
return () => this.deleteUsers() return () => this.deleteUsers()
} case 'resend_confirmation':
case 'resend_confirmation': {
return () => this.resendConfirmationEmail() return () => this.resendConfirmationEmail()
} case 'disable_mfa':
case 'disable_mfa': {
return () => this.disableMFA() return () => this.disableMFA()
} case 'statuses':
case 'statuses': {
return () => return () =>
this.$router.push(`/users/\$${this.users[0].id}/admin_view`) this.$router.push(`/users/\$${this.users[0].id}/admin_view`)
} case 'require_password_change':
case 'require_password_change': {
return () => this.requirePasswordChange() return () => this.requirePasswordChange()
}
default: default:
throw new Error(`Unknown action group: ${name}`) throw new Error(`Unknown action group: ${name}`)
} }
@ -277,24 +272,22 @@ const ModerationTools = {
} }
switch (group) { switch (group) {
case 'action': { case 'action':
return true return true
} case 'rights':
case 'rights': {
return this.canGrantRole(name, value) return this.canGrantRole(name, value)
} case 'state':
case 'state': {
return this.canChangeState(name, value) return this.canChangeState(name, value)
} case 'mrf_tag':
case 'mrf_tag': {
return this.canUseTagPolicy return this.canUseTagPolicy
}
default: { default: {
throw new Error(`Unknown moderation group: ${group}`) throw new Error(`Unknown moderation group: ${group}`)
} }
} }
}) })
.reduce((acc, entry, index) => { .reduce((acc, entry, index) => {
// Removing any double separators as well
// as separators at very end and bery beginning
if (entry === 'separator') { if (entry === 'separator') {
if ( if (
acc.length === 0 || acc.length === 0 ||
@ -363,12 +356,16 @@ const ModerationTools = {
const result = new Set() const result = new Set()
// Each tag can have three states for given group of users
TAGS.forEach((tag) => { TAGS.forEach((tag) => {
if (present.has(tag) && missing.has(tag)) { if (present.has(tag) && missing.has(tag)) {
// Some users have tag, some don't: "~tag"
result.add(`~${tag}`) result.add(`~${tag}`)
} else if (missing.has(tag)) { } else if (missing.has(tag)) {
// No users have tag: "!tag"
result.add(`!${tag}`) result.add(`!${tag}`)
} else { } else {
// All users have tag: "tag"
result.add(tag) result.add(tag)
} }
}) })

View file

@ -43,7 +43,7 @@
> >
<td>{{ entry.instance }}</td> <td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''"> <td v-if="entry.reason === ''">
{{ $t("general.not_applicable") }} {{ $t("about.mrf.simple.not_applicable") }}
</td> </td>
<td v-else> <td v-else>
{{ entry.reason }} {{ entry.reason }}
@ -70,7 +70,7 @@
> >
<td>{{ entry.instance }}</td> <td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''"> <td v-if="entry.reason === ''">
{{ $t("general.not_applicable") }} {{ $t("about.mrf.simple.not_applicable") }}
</td> </td>
<td v-else> <td v-else>
{{ entry.reason }} {{ entry.reason }}
@ -97,7 +97,7 @@
> >
<td>{{ entry.instance }}</td> <td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''"> <td v-if="entry.reason === ''">
{{ $t("general.not_applicable") }} {{ $t("about.mrf.simple.not_applicable") }}
</td> </td>
<td v-else> <td v-else>
{{ entry.reason }} {{ entry.reason }}
@ -124,7 +124,7 @@
> >
<td>{{ entry.instance }}</td> <td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''"> <td v-if="entry.reason === ''">
{{ $t("general.not_applicable") }} {{ $t("about.mrf.simple.not_applicable") }}
</td> </td>
<td v-else> <td v-else>
{{ entry.reason }} {{ entry.reason }}
@ -151,7 +151,7 @@
> >
<td>{{ entry.instance }}</td> <td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''"> <td v-if="entry.reason === ''">
{{ $t("general.not_applicable") }} {{ $t("about.mrf.simple.not_applicable") }}
</td> </td>
<td v-else> <td v-else>
{{ entry.reason }} {{ entry.reason }}
@ -178,7 +178,7 @@
> >
<td>{{ entry.instance }}</td> <td>{{ entry.instance }}</td>
<td v-if="entry.reason === ''"> <td v-if="entry.reason === ''">
{{ $t("general.not_applicable") }} {{ $t("about.mrf.simple.not_applicable") }}
</td> </td>
<td v-else> <td v-else>
{{ entry.reason }} {{ entry.reason }}

View file

@ -1,95 +0,0 @@
import Checkbox from 'src/components/checkbox/checkbox.vue'
import Select from 'src/components/select/select.vue'
import Status from 'src/components/status/status.vue'
import { parseStatus } from 'src/services/entity_normalizer/entity_normalizer.service.js'
const AdminStatusCard = {
props: {
statusDetails: {
type: Object,
required: true,
validator(u) {
return typeof u.id === 'string'
},
},
},
data() {
return {
jsonExpanded: false,
statusCache: undefined,
}
},
computed: {
isSensitive() {
return this.statusDetails.sensitive === true
},
visibility() {
return this.statusDetails.visibility
},
},
methods: {
changeSensitivity(v) {
this.$store
.dispatch('adminChangeStatusScope', {
opts: { id: this.statusDetails.id, sensitive: v },
})
.then((res) => parseStatus(res))
.then((s) => (this.statusCache = s))
},
changeVisibility(v) {
this.$store
.dispatch('adminChangeStatusScope', {
opts: { id: this.statusDetails.id, visibility: v },
})
.then((res) => parseStatus(res))
.then((s) => (this.statusCache = s))
},
/**
* 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, opts) {
const restricted = []
const s = this.$refs.userList.getSelected()
s.forEach((u) => {
if (
restricted.includes(action) !== false ||
u.id !== this.$store.state.users.currentUser.id
) {
this.$store.dispatch(action, {
id: this.statusDetails.id,
...(opts || {}),
})
}
})
this.reset()
},
},
components: {
Checkbox,
Select,
Status,
},
/**
* fetch and cache status info
*/
mounted() {
this.$store
.dispatch('adminChangeStatusScope', {
opts: { id: this.statusDetails.id },
})
.then((res) => parseStatus(res))
.then((s) => (this.statusCache = s))
},
}
export default AdminStatusCard

View file

@ -1,106 +0,0 @@
<template>
<div class="setting-item">
<h2> {{ $t('admin_dash.users.title_info') }}: </h2>
<ul
class="setting-list"
>
<li>
<span> {{ $t('admin_dash.users.status_id') }}: {{ statusDetails.id }} </span>
</li>
<li>
<span> {{ $t('admin_dash.users.created_at') }}: {{ new Date(statusDetails.created_at).toLocaleString() }} </span>
</li>
<li>
<span v-if="statusDetails.edited_at !== null"> {{ $t('admin_dash.users.edited_at') }}: {{ new Date(statusDetails.edited_at).toLocaleString() }} </span>
</li>
</ul>
<h2> {{ $t('admin_dash.users.title_content') }}: </h2>
<ul
class="setting-list"
>
<li>
<Status
v-if="typeof(statusCache) !== 'undefined'"
class="Notification"
:compact="true"
:statusoid="statusCache"
@interacted="false"
/>
</li>
<p> action dropdown thingy </p>
<!--
<li>
<button
class="button button-default btn"
type="button"
@click="deleteStatus(status.id)"
>
{{ $t('admin_dash.users.delete_status') }}
</button>
</li>
<li>
<Checkbox
:model-value="isSensitive"
@update:model-value="v => changeSensitivity(v)"
>
{{ $t('admin_dash.users.content_nsfw') }}
</Checkbox>
</li>
<li>
<Select
:model-value="visibility"
@update:model-value="v => changeVisibility(v)"
>
<option
value="public"
>
{{ $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="statusDetails.url"> {{ $t('admin_dash.users.link_source') }} </a>
</li>
-->
</ul>
<!--
<div v-if="!jsonExpanded">
<button
class="button button-default btn"
type="button"
@click="jsonExpanded = !jsonExpanded"
>
{{ $t('admin_dash.users.expand_raw_info') }}
</button>
</div>
<div v-else>
<button
class="button button-default btn"
type="button"
@click="jsonExpanded = !jsonExpanded"
>
{{ $t('admin_dash.users.collapse_raw_info') }}
</button>
<h2> {{ $t('admin_dash.users.title_details') }} </h2>
<pre> {{ JSON.stringify(statusDetails, null, 2) }} </pre>
</div>
-->
</div>
</template>
<script src="./admin_status_card.js"></script>

View file

@ -3,7 +3,7 @@ import { defineAsyncComponent } from 'vue'
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue' import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
import ModerationTools from 'src/components/moderation_tools/moderation_tools.vue' import ModerationTools from 'src/components/moderation_tools/moderation_tools.vue'
const AdminCard = { const AdminUserCard = {
props: { props: {
userId: { userId: {
type: String, type: String,
@ -17,9 +17,6 @@ const AdminCard = {
user() { user() {
return this.$store.getters.findUser(this.userId) return this.$store.getters.findUser(this.userId)
}, },
relationship() {
return this.$store.getters.relationship(this.userId)
},
isAdmin() { isAdmin() {
return this.user.rights.admin return this.user.rights.admin
}, },
@ -32,4 +29,4 @@ const AdminCard = {
}, },
} }
export default AdminCard export default AdminUserCard

View file

@ -1,4 +1,4 @@
.AdminCard { .AdminUserCard {
width: 100%; width: 100%;
.right-side { .right-side {

View file

@ -8,7 +8,7 @@
</template> </template>
<template v-else> <template v-else>
<BasicUserCard <BasicUserCard
class="AdminCard" class="AdminUserCard"
:user="user" :user="user"
show-line-labels show-line-labels
> >
@ -102,6 +102,6 @@
</template> </template>
</template> </template>
<script src="./admin_card.js"></script> <script src="./admin_user_card.js"></script>
<style lang="scss" src="./admin_card.scss"></style> <style lang="scss" src="./admin_user_card.scss"></style>

View file

@ -105,7 +105,7 @@ const FrontendsTab = {
const ref = suggestRef || this.getSuggestedRef(frontend) const ref = suggestRef || this.getSuggestedRef(frontend)
const { name } = frontend const { name } = frontend
useAdminSettingsStore.updateAdminDraft({ useAdminSettingsStore().updateAdminDraft({
path: [':pleroma', ':frontends', ':primary'], path: [':pleroma', ':frontends', ':primary'],
value: { name, ref }, value: { name, ref },
}) })

View file

@ -112,19 +112,19 @@ const LinksTab = {
}, },
methods: { methods: {
checkRel(e) { checkRel(e) {
useAdminSettingsStore.updateAdminDraft({ useAdminSettingsStore().updateAdminDraft({
path: [':pleroma', 'Pleroma.Formatter', ':rel'], path: [':pleroma', 'Pleroma.Formatter', ':rel'],
value: e ? '' : false, value: e ? '' : false,
}) })
}, },
checkClass(e) { checkClass(e) {
useAdminSettingsStore.updateAdminDraft({ useAdminSettingsStore().updateAdminDraft({
path: [':pleroma', 'Pleroma.Formatter', ':class'], path: [':pleroma', 'Pleroma.Formatter', ':class'],
value: e ? '' : false, value: e ? '' : false,
}) })
}, },
checkTruncate(e) { checkTruncate(e) {
useAdminSettingsStore.updateAdminDraft({ useAdminSettingsStore().updateAdminDraft({
path: [':pleroma', 'Pleroma.Formatter', ':truncate'], path: [':pleroma', 'Pleroma.Formatter', ':truncate'],
value: e ? 20 : false, value: e ? 20 : false,
}) })

View file

@ -5,10 +5,8 @@ import Checkbox from 'src/components/checkbox/checkbox.vue'
import GenericConfirm from 'src/components/confirm_modal/generic_confirm.vue' import GenericConfirm from 'src/components/confirm_modal/generic_confirm.vue'
import List from 'src/components/list/list.vue' import List from 'src/components/list/list.vue'
import ModerationTools from 'src/components/moderation_tools/moderation_tools.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 Select from 'src/components/select/select.vue'
import AdminCard from 'src/components/settings_modal/admin_tabs/admin_card.vue' import AdminUserCard from 'src/components/settings_modal/admin_tabs/admin_user_card.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import { useAdminSettingsStore } from 'src/stores/admin_settings.js' import { useAdminSettingsStore } from 'src/stores/admin_settings.js'
@ -18,18 +16,10 @@ const UsersTab = {
Select, Select,
BasicUserCard, BasicUserCard,
List, List,
ProgressButton, AdminUserCard,
AdminCard,
TabSwitcher,
ModerationTools, ModerationTools,
GenericConfirm, GenericConfirm,
}, },
provide() {
return {
defaultDraftMode: true,
defaultSource: 'admin',
}
},
data() { data() {
return { return {
filtersOrigin: 'local', filtersOrigin: 'local',

View file

@ -131,7 +131,7 @@
<ModerationTools :users="selected" /> <ModerationTools :users="selected" />
</template> </template>
<template #item="{item}"> <template #item="{item}">
<AdminCard :user-id="item.id" /> <AdminUserCard :user-id="item.id" />
</template> </template>
<template #load> <template #load>
<span> loading </span> <span> loading </span>

View file

@ -133,7 +133,7 @@ export default {
}, },
set(value) { set(value) {
if (this.realSource === 'admin' || this.path == null) { if (this.realSource === 'admin' || this.path == null) {
useAdminSettingsStore.updateAdminDraft({ useAdminSettingsStore().updateAdminDraft({
path: this.canonPath, path: this.canonPath,
value, value,
}) })
@ -254,7 +254,7 @@ export default {
this.$store.dispatch('setProfileOption', { name: k, value: v }) this.$store.dispatch('setProfileOption', { name: k, value: v })
case 'admin': case 'admin':
return (k, v) => return (k, v) =>
useAdminSettingsStore.pushAdminSetting({ path: k, value: v }) useAdminSettingsStore().pushAdminSetting({ path: k, value: v })
default: default:
return (readPath, value) => { return (readPath, value) => {
const writePath = `${readPath}` const writePath = `${readPath}`

View file

@ -233,10 +233,10 @@ const SettingsModal = {
return clone return clone
}, },
resetAdminDraft() { resetAdminDraft() {
useAdminSettingsStore.resetAdminDraft() useAdminSettingsStore().resetAdminDraft()
}, },
pushAdminDraft() { pushAdminDraft() {
useAdminSettingsStore.pushAdminDraft() useAdminSettingsStore().pushAdminDraft()
}, },
...mapActions(useInterfaceStore, [ ...mapActions(useInterfaceStore, [
'temporaryChangesRevert', 'temporaryChangesRevert',

View file

@ -4,7 +4,7 @@
ref="tabSwitcher" ref="tabSwitcher"
class="settings-admin-content settings_tab-switcher" class="settings-admin-content settings_tab-switcher"
:side-tab-bar="true" :side-tab-bar="true"
:scrollable-tabs="true" :scrollable-tabs
:render-only-focused="true" :render-only-focused="true"
:body-scroll-lock="bodyLock" :body-scroll-lock="bodyLock"
> >
@ -50,7 +50,6 @@
</div> </div>
<div <div
v-if="adminDbLoaded"
:label="$t('admin_dash.tabs.users')" :label="$t('admin_dash.tabs.users')"
icon="user" icon="user"
data-tab-name="users" data-tab-name="users"

View file

@ -2,7 +2,7 @@
<vertical-tab-switcher <vertical-tab-switcher
ref="tabSwitcher" ref="tabSwitcher"
class="settings_tab-switcher" class="settings_tab-switcher"
:scrollable-tabs="true" :scrollable-tabs
:body-scroll-lock="bodyLock" :body-scroll-lock="bodyLock"
:hide-header="navHideHeader" :hide-header="navHideHeader"
> >

View file

@ -16,15 +16,6 @@ const MutesAndBlocks = {
data() { data() {
return { return {
activeTab: 'profile', activeTab: 'profile',
mutesLoading: false,
mutesError: null,
mutesBottomedOut: false,
blocksLoading: false,
blocksError: null,
blocksBottomedOut: false,
domainsLoading: false,
domainsError: null,
domainsBottomedOut: false,
} }
}, },
created() { created() {

View file

@ -1,7 +1,7 @@
<template> <template>
<tab-switcher <tab-switcher
class="mutes-and-blocks-tab" class="mutes-and-blocks-tab"
:scrollable-tabs="true" :scrollable-tabs
> >
<div <div
class="blocks" class="blocks"

View file

@ -204,6 +204,7 @@ const UserProfile = {
List, List,
FollowCard, FollowCard,
TabSwitcher, TabSwitcher,
Conversation,
}, },
} }

View file

@ -60,7 +60,7 @@ const UserProfileAdminView = {
Checkbox, Checkbox,
}, },
watch: { watch: {
godmode() { fetchOptions() {
this.$refs.list.reset() this.$refs.list.reset()
}, },
}, },

View file

@ -385,9 +385,6 @@
"selectable_list": { "selectable_list": {
"select_all": "Select all" "select_all": "Select all"
}, },
"page_list": {
"load_more": "Load more"
},
"settings": { "settings": {
"invalid_settings_imported": "Error importing settings", "invalid_settings_imported": "Error importing settings",
"add_language": "Add fallback language", "add_language": "Add fallback language",