From 50b919fb235fe95c4f37e54c6bc2d6da2fb84083 Mon Sep 17 00:00:00 2001 From: Sol Fisher Romanoff Date: Sat, 12 Nov 2022 21:35:07 +0200 Subject: [PATCH 01/11] Create layout for users moderation tab --- src/components/mod_modal/mod_modal_content.js | 6 +- .../mod_modal/mod_modal_content.vue | 7 + .../mod_modal/tabs/users_tab/users_tab.js | 70 ++++++++ .../mod_modal/tabs/users_tab/users_tab.scss | 25 +++ .../mod_modal/tabs/users_tab/users_tab.vue | 170 ++++++++++++++++++ src/i18n/en.json | 15 +- 6 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 src/components/mod_modal/tabs/users_tab/users_tab.js create mode 100644 src/components/mod_modal/tabs/users_tab/users_tab.scss create mode 100644 src/components/mod_modal/tabs/users_tab/users_tab.vue diff --git a/src/components/mod_modal/mod_modal_content.js b/src/components/mod_modal/mod_modal_content.js index e0ba6259..f1637e73 100644 --- a/src/components/mod_modal/mod_modal_content.js +++ b/src/components/mod_modal/mod_modal_content.js @@ -2,7 +2,7 @@ import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' import ReportsTab from './tabs/reports_tab/reports_tab.vue' // import StatusesTab from './tabs/statuses_tab.vue' -// import UsersTab from './tabs/users_tab.vue' +import UsersTab from './tabs/users_tab/users_tab.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { @@ -21,9 +21,9 @@ const ModModalContent = { components: { TabSwitcher, - ReportsTab + ReportsTab, // StatusesTab, - // UsersTab + UsersTab }, computed: { open () { diff --git a/src/components/mod_modal/mod_modal_content.vue b/src/components/mod_modal/mod_modal_content.vue index 6fa32be1..c4b964b9 100644 --- a/src/components/mod_modal/mod_modal_content.vue +++ b/src/components/mod_modal/mod_modal_content.vue @@ -13,6 +13,13 @@ > +
+ +
diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.js b/src/components/mod_modal/tabs/users_tab/users_tab.js new file mode 100644 index 00000000..025334e2 --- /dev/null +++ b/src/components/mod_modal/tabs/users_tab/users_tab.js @@ -0,0 +1,70 @@ +import Popover from 'src/components/popover/popover.vue' + +import { forEach } from 'lodash' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faFilter, + faSearch +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faFilter, + faSearch +) + +const UsersTab = { + data () { + return { + accountType: { + local: true, + external: false, + all: false + }, + status: { + active: true, + deactivated: false, + pending: false, + unconfirmed: false, + all: false + }, + actorType: { + person: true, + bot: true, + application: true, + all: true + } + } + }, + components: { + Popover + }, + methods: { + setAccountType (type) { + if (type === 'all') { + forEach(this.accountType, (k, v) => { this.accountType[v] = true }) + } else { + forEach(this.accountType, (k, v) => { this.accountType[v] = false }) + this.accountType[type] = true + } + }, + setStatus (status) { + if (status === 'all') { + forEach(this.status, (k, v) => { this.status[v] = true }) + } else { + forEach(this.status, (k, v) => { this.status[v] = false }) + this.status[status] = true + } + }, + setActorType (type) { + if (type === 'all') { + forEach(this.actorType, (k, v) => { this.actorType[v] = true }) + } else { + forEach(this.actorType, (k, v) => { this.actorType[v] = false }) + this.actorType[type] = true + } + } + } +} + +export default UsersTab diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.scss b/src/components/mod_modal/tabs/users_tab/users_tab.scss new file mode 100644 index 00000000..09a323ee --- /dev/null +++ b/src/components/mod_modal/tabs/users_tab/users_tab.scss @@ -0,0 +1,25 @@ +@import '../../../../_variables.scss'; + +.reports-header .right-side { + display: flex; + align-items: center; + + .search-input-container { + padding: 0.8rem; + display: flex; + justify-content: center; + align-items: center; + + .search-input { + width: 100%; + line-height: 1.125rem; + font-size: 1rem; + padding: 0.5rem; + box-sizing: border-box; + } + + .search-icon { + margin-right: 0.3em; + } + } +} diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.vue b/src/components/mod_modal/tabs/users_tab/users_tab.vue new file mode 100644 index 00000000..b540fb00 --- /dev/null +++ b/src/components/mod_modal/tabs/users_tab/users_tab.vue @@ -0,0 +1,170 @@ + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index 534f1c1c..fb4cf9e3 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -294,7 +294,20 @@ "tags": "Set post restrictions" }, "statuses": "Posts", - "users": "Users" + "users": { + "users": "Users", + "filter": { + "active": "Active", + "all": "All accounts", + "application": "Application", + "bot": "Bot", + "deactivated": "Deactivated", + "external": "External", + "local": "Local", + "pending": "Pending Approval", + "person": "Person", + "unconfirmed": "Unconfirmed" + } }, "nav": { "about": "About", -- 2.34.1 From db7395b5021e1768ea666a41c8ea5528ecec404e Mon Sep 17 00:00:00 2001 From: Sol Fisher Romanoff Date: Sun, 13 Nov 2022 20:04:17 +0200 Subject: [PATCH 02/11] Implement admin user list API endpoint --- src/modules/users.js | 12 ++++++++++ src/services/api/api.service.js | 24 +++++++++++++++++++ .../entity_normalizer.service.js | 10 ++++++++ 3 files changed, 46 insertions(+) diff --git a/src/modules/users.js b/src/modules/users.js index c63b93de..c236d600 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -185,6 +185,9 @@ export const mutations = { user['followedTagIds'] = [] } }, + adminSetUsers (state, users) { + state.adminUsers = users + }, addNewUsers (state, users) { each(users, (user) => { if (user.relationship) { @@ -294,6 +297,7 @@ export const defaultState = { currentUser: false, users: [], usersObject: {}, + adminUsers: [], signUpPending: false, signUpErrors: [], relationships: {}, @@ -306,6 +310,14 @@ const users = { mutations, getters, actions: { + fetchUsers (store, params = false) { + return store.rootState.api.backendInteractor.fetchUsers(params) + .then((users) => { + store.commit('adminSetUsers', users) + users.forEach(user => store.dispatch('fetchUserIfMissing', user.id)) + return users + }) + }, fetchUserIfMissing (store, id) { if (!store.getters.findUser(id)) { store.dispatch('fetchUser', id) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 0f8b75a4..da4cc238 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -557,6 +557,29 @@ const fetchStatusHistory = ({ status, credentials }) => { }) } +const fetchUsers = ({ filters, name, page, actorTypes, credentials }) => { + const url = ADMIN_USERS_URL + const params = [] + + if (filters) { + params.push(['filters', filters.join(',')]) + } + if (name) { + params.push(['name', name]) + } + if (page) { + params.push(['page', page]) + } + if (actorTypes) { + actorTypes.forEach(type => (params.push(['actor_types[]', type]))) + } + + const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&') + return promisedRequest({ url: url + `?${queryString}`, credentials }) + .then((data) => data.users) + .then((data) => data.map(parseUser)) +} + const tagUser = ({ tag, credentials, user }) => { const screenName = user.screen_name const form = { @@ -1762,6 +1785,7 @@ const apiService = { fetchBlocks, fetchOAuthTokens, revokeOAuthToken, + fetchUsers, tagUser, untagUser, deleteUser, diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index c54ce3e2..04a474a8 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -43,6 +43,9 @@ export const parseUser = (data) => { // case for users in "mentions" property for statuses in MastoAPI const mastoShort = masto && !data.hasOwnProperty('avatar') + // account format from the admin API + const admin = data.hasOwnProperty('actor_type') + output.id = String(data.id) output._original = data // used for server-side settings @@ -139,6 +142,13 @@ export const parseUser = (data) => { // TODO: handle is_local output.is_local = !output.screen_name.includes('@') + } else if (admin) { + output.screen_name = data.nickname + output.name = data.display_name + output.profile_image_url = data.avatar + output.profile_image_url_original = data.avatar + output.is_local = data.local + output.emoji = [] } else { output.screen_name = data.screen_name -- 2.34.1 From b025b6f10f834e007e9b49b29f153d45dfc3f750 Mon Sep 17 00:00:00 2001 From: Sol Fisher Romanoff Date: Sun, 13 Nov 2022 20:05:36 +0200 Subject: [PATCH 03/11] Add user list, querying and pagination to moderation --- src/components/mod_modal/mod_modal.scss | 1 + src/components/mod_modal/mod_modal.vue | 3 + .../mod_modal/tabs/users_tab/users_tab.js | 90 +++++++++++++------ .../mod_modal/tabs/users_tab/users_tab.vue | 71 ++++++++++----- src/i18n/en.json | 2 + 5 files changed, 122 insertions(+), 45 deletions(-) diff --git a/src/components/mod_modal/mod_modal.scss b/src/components/mod_modal/mod_modal.scss index 4821df74..b4f5db5c 100644 --- a/src/components/mod_modal/mod_modal.scss +++ b/src/components/mod_modal/mod_modal.scss @@ -39,6 +39,7 @@ .panel-body { height: inherit; + overflow-y: hidden; } } } diff --git a/src/components/mod_modal/mod_modal.vue b/src/components/mod_modal/mod_modal.vue index 64bbf021..f6b529a0 100644 --- a/src/components/mod_modal/mod_modal.vue +++ b/src/components/mod_modal/mod_modal.vue @@ -35,6 +35,9 @@
+ diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.js b/src/components/mod_modal/tabs/users_tab/users_tab.js index 025334e2..03447742 100644 --- a/src/components/mod_modal/tabs/users_tab/users_tab.js +++ b/src/components/mod_modal/tabs/users_tab/users_tab.js @@ -1,6 +1,8 @@ +import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue' +import ModerationTools from 'src/components/moderation_tools/moderation_tools.vue' import Popover from 'src/components/popover/popover.vue' -import { forEach } from 'lodash' +import { forEach, every, findKey } from 'lodash' import { library } from '@fortawesome/fontawesome-svg-core' import { @@ -16,53 +18,91 @@ library.add( const UsersTab = { data () { return { + searchTerm: null, + page: 1, accountType: { local: true, - external: false, - all: false + external: false }, status: { active: true, deactivated: false, - pending: false, - unconfirmed: false, - all: false + need_approval: false, + unconfirmed: false }, actorType: { - person: true, - bot: true, - application: true, - all: true + Person: false, + Service: false, + Application: false } } }, components: { + BasicUserCard, + ModerationTools, Popover }, + created () { + this.query() + }, + computed: { + users () { return this.$store.state.users.adminUsers }, + isActive () { + const tabSwitcher = this.$parent + console.log(this.users) + return tabSwitcher ? tabSwitcher.isActive('users') : false + } + }, methods: { - setAccountType (type) { - if (type === 'all') { - forEach(this.accountType, (k, v) => { this.accountType[v] = true }) - } else { - forEach(this.accountType, (k, v) => { this.accountType[v] = false }) + all (filter) { return every(filter, _ => !_) }, + setAccountType (type = false) { + forEach(this.accountType, (k, v) => { this.accountType[v] = false }) + if (type) { this.accountType[type] = true } + + this.query() }, - setStatus (status) { - if (status === 'all') { - forEach(this.status, (k, v) => { this.status[v] = true }) - } else { - forEach(this.status, (k, v) => { this.status[v] = false }) + setStatus (status = false) { + forEach(this.status, (k, v) => { this.status[v] = false }) + if (status) { this.status[status] = true } + + this.query() }, - setActorType (type) { - if (type === 'all') { - forEach(this.actorType, (k, v) => { this.actorType[v] = true }) - } else { - forEach(this.actorType, (k, v) => { this.actorType[v] = false }) + setActorType (type = false) { + forEach(this.actorType, (k, v) => { this.actorType[v] = false }) + if (type) { this.actorType[type] = true } + + this.query() + }, + prevPage () { + this.page-- + this.query() + }, + nextPage () { + this.page++ + this.query() + }, + query () { + const params = {} + params.actorTypes = [findKey(this.actorType, _ => _)].filter(Boolean) + params.filters = [ + findKey(this.status, _ => _), + findKey(this.accountType, _ => _) + ].filter(Boolean) + + if (this.searchTerm) { + params.name = this.searchTerm + } + if (this.page > 1) { + params.page = this.page + } + + this.$store.dispatch('fetchUsers', params) } } } diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.vue b/src/components/mod_modal/tabs/users_tab/users_tab.vue index b540fb00..cd3d77b6 100644 --- a/src/components/mod_modal/tabs/users_tab/users_tab.vue +++ b/src/components/mod_modal/tabs/users_tab/users_tab.vue @@ -15,7 +15,7 @@ v-model="searchTerm" class="search-input" :placeholder="$t('nav.search')" - @keyup.enter="newQuery(searchTerm)" + @keyup.enter="query()" /> {{ $t('moderation.users.filter.local') }}
{{ $t('moderation.users.filter.active') }} + + +
+ + +
+
diff --git a/src/i18n/en.json b/src/i18n/en.json index fb4cf9e3..588127d9 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -294,6 +294,8 @@ "tags": "Set post restrictions" }, "statuses": "Posts", + "next": "Next page", + "previous": "Previous page", "users": { "users": "Users", "filter": { -- 2.34.1 From 0b071b77b29bf35359c42275b2737689c99a3460 Mon Sep 17 00:00:00 2001 From: Sol Fisher Romanoff Date: Sun, 13 Nov 2022 22:50:09 +0200 Subject: [PATCH 04/11] Add message if no results found --- src/components/mod_modal/tabs/users_tab/users_tab.vue | 3 +++ src/i18n/en.json | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.vue b/src/components/mod_modal/tabs/users_tab/users_tab.vue index cd3d77b6..1768cd24 100644 --- a/src/components/mod_modal/tabs/users_tab/users_tab.vue +++ b/src/components/mod_modal/tabs/users_tab/users_tab.vue @@ -161,6 +161,9 @@
+
+

{{ $t('moderation.users.no_results') }}

+
Date: Mon, 14 Nov 2022 19:18:34 +0200 Subject: [PATCH 05/11] Align pagination and moderation buttons --- src/components/mod_modal/mod_modal.scss | 9 ++++ .../mod_modal/tabs/users_tab/users_tab.scss | 45 +++++++++++++------ .../mod_modal/tabs/users_tab/users_tab.vue | 9 ++-- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/components/mod_modal/mod_modal.scss b/src/components/mod_modal/mod_modal.scss index b4f5db5c..4e9cbb91 100644 --- a/src/components/mod_modal/mod_modal.scss +++ b/src/components/mod_modal/mod_modal.scss @@ -41,5 +41,14 @@ height: inherit; overflow-y: hidden; } + + .pagination-container { + display: flex; + justify-content: right; + + .btn { + margin-left: 0.6em; + } + } } } diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.scss b/src/components/mod_modal/tabs/users_tab/users_tab.scss index 09a323ee..6127b9aa 100644 --- a/src/components/mod_modal/tabs/users_tab/users_tab.scss +++ b/src/components/mod_modal/tabs/users_tab/users_tab.scss @@ -1,25 +1,44 @@ @import '../../../../_variables.scss'; -.reports-header .right-side { +.users-header { display: flex; align-items: center; + justify-content: space-between; - .search-input-container { - padding: 0.8rem; + .right-side { display: flex; - justify-content: center; align-items: center; - .search-input { - width: 100%; - line-height: 1.125rem; - font-size: 1rem; - padding: 0.5rem; - box-sizing: border-box; - } + .search-input-container { + padding: 0.8rem; + display: flex; + justify-content: center; + align-items: center; - .search-icon { - margin-right: 0.3em; + .search-input { + width: 100%; + line-height: 1.125rem; + font-size: 1rem; + padding: 0.5rem; + box-sizing: border-box; + } + + .search-icon { + margin-right: 0.3em; + } } } } + +.users .user { + display: flex; + flex-direction: row; + + .user-moderation { + padding-top: 0.6em; + } + + .basic-user-card { + width: 0; + } +} diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.vue b/src/components/mod_modal/tabs/users_tab/users_tab.vue index 1768cd24..10a86b2a 100644 --- a/src/components/mod_modal/tabs/users_tab/users_tab.vue +++ b/src/components/mod_modal/tabs/users_tab/users_tab.vue @@ -1,7 +1,7 @@ @@ -170,7 +166,11 @@ class="user" > - +
diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js index 2469327a..c2da3a69 100644 --- a/src/components/moderation_tools/moderation_tools.js +++ b/src/components/moderation_tools/moderation_tools.js @@ -16,7 +16,8 @@ const QUARANTINE = 'mrf_tag:quarantine' const ModerationTools = { props: [ - 'user' + 'user', + 'extended' ], data () { return { @@ -30,7 +31,10 @@ const ModerationTools = { QUARANTINE }, showDeleteUserDialog: false, - toggled: false + showPasswordTokenDialog: false, + toggled: false, + passwordResetToken: {}, + bot: this.user.bot } }, components: { @@ -83,6 +87,9 @@ const ModerationTools = { deleteUserDialog (show) { this.showDeleteUserDialog = show }, + passwordTokenDialog (show) { + this.showPasswordTokenDialog = show + }, deleteUser () { const store = this.$store const user = this.user @@ -97,6 +104,29 @@ const ModerationTools = { } }) }, + getPasswordResetToken () { + this.$store.state.api.backendInteractor.getPasswordResetToken({ nickname: this.user.screen_name }) + .then(data => { + this.passwordResetToken = data + this.passwordTokenDialog(true) + }) + }, + forcePasswordReset () { + this.$store.state.api.backendInteractor.forcePasswordReset({ nickname: this.user.screen_name }) + }, + forceDisableMFA () { + this.$store.state.api.backendInteractor.forceDisableMFA({ nickname: this.user.screen_name }) + }, + toggleBot () { + const params = { bot: !this.bot } + + this.$store.state.api.backendInteractor + .updateProfile({ params }) + .then((user) => { + this.$store.commit('addNewUsers', [user]) + this.bot = !this.bot + }) + }, setToggled (value) { this.toggled = value } diff --git a/src/components/moderation_tools/moderation_tools.vue b/src/components/moderation_tools/moderation_tools.vue index 75ea08cc..f93f4847 100644 --- a/src/components/moderation_tools/moderation_tools.vue +++ b/src/components/moderation_tools/moderation_tools.vue @@ -120,6 +120,37 @@ {{ $t('user_card.admin_menu.quarantine') }}
+ + + +

+ {{ $t('user_card.admin_menu.password_reset_token_content', { token: passwordResetToken.token }) }} + {{ passwordResetToken.link }} +

+ +
diff --git a/src/i18n/en.json b/src/i18n/en.json index 21fb6f99..e91be01d 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -1109,17 +1109,23 @@ "user_card": { "admin_menu": { "activate_account": "Activate account", + "convert_to": "Convert to { type }", "deactivate_account": "Deactivate account", "delete_account": "Delete account", "delete_user": "Delete user", "delete_user_data_and_deactivate_confirmation": "This will permanently delete the data from this account and deactivate it. Are you absolutely sure?", "disable_any_subscription": "Disallow following user at all", + "disable_mfa": "Disable multi-factor authentication", "disable_remote_subscription": "Disallow following user from remote instances", "force_nsfw": "Mark all posts as NSFW", + "force_password_reset": "Require password reset on next login", "force_unlisted": "Force posts to be unlisted", + "get_password_reset_token": "Get password reset token", "grant_admin": "Grant Admin", "grant_moderator": "Grant Moderator", "moderation": "Moderation", + "password_reset_token": "Password reset token", + "password_reset_token_content": "Password reset token has been generated: { token }\nYou can also use this link to reset the password: ", "quarantine": "Disallow user posts from federating", "revoke_admin": "Revoke Admin", "revoke_moderator": "Revoke Moderator", diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index da4cc238..126bfc8a 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -23,6 +23,9 @@ const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read' const ADMIN_REPORTS_URL = '/api/v1/pleroma/admin/reports' const ADMIN_REPORT_NOTES_URL = id => `/api/v1/pleroma/admin/reports/${id}/notes` const ADMIN_REPORT_NOTE_URL = (report, note) => `/api/v1/pleroma/admin/reports/${report}/notes/${note}` +const ADMIN_PASSWORD_RESET_TOKEN_URL = nickname => `/api/v1/pleroma/admin/users/${nickname}/password_reset` +const ADMIN_FORCE_PASSWORD_RESET_URL = '/api/v1/pleroma/admin/users/force_password_reset' +const ADMIN_DISABLE_MFA_URL = '/api/v1/pleroma/admin/users/disable_mfa' const MFA_SETTINGS_URL = '/api/pleroma/accounts/mfa' const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes' @@ -717,6 +720,31 @@ const deleteNoteFromReport = ({ report, note, credentials }) => { }) } +const getPasswordResetToken = ({ nickname, credentials }) => { + const url = ADMIN_PASSWORD_RESET_TOKEN_URL(nickname) + + return fetch(url, { headers: authHeaders(credentials) }) + .then(data => data.json()) +} + +const forcePasswordReset = ({ nickname, credentials }) => { + return promisedRequest({ + url: ADMIN_FORCE_PASSWORD_RESET_URL, + method: 'PATCH', + payload: { nicknames: [nickname] }, + credentials + }) +} + +const forceDisableMFA = ({ nickname, credentials }) => { + return promisedRequest({ + url: ADMIN_DISABLE_MFA_URL, + method: 'PUT', + payload: { nickname }, + credentials + }) +} + const fetchTimeline = ({ timeline, credentials, @@ -1793,6 +1821,9 @@ const apiService = { deleteRight, activateUser, deactivateUser, + getPasswordResetToken, + forcePasswordReset, + forceDisableMFA, register, getCaptcha, updateProfileImages, diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 04a474a8..14f76cc9 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -143,6 +143,7 @@ export const parseUser = (data) => { // TODO: handle is_local output.is_local = !output.screen_name.includes('@') } else if (admin) { + output.bot = data.actor_type === 'Service' output.screen_name = data.nickname output.name = data.display_name output.profile_image_url = data.avatar -- 2.34.1 From d09cfe76db57e4224f6cfc2acf2f7f90cb953ca8 Mon Sep 17 00:00:00 2001 From: Sol Fisher Romanoff Date: Mon, 21 Nov 2022 13:19:54 +0200 Subject: [PATCH 08/11] Allow popovers to overflow --- src/components/mod_modal/mod_modal.scss | 1 - src/components/mod_modal/tabs/users_tab/users_tab.vue | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/mod_modal/mod_modal.scss b/src/components/mod_modal/mod_modal.scss index 4e9cbb91..f0882f97 100644 --- a/src/components/mod_modal/mod_modal.scss +++ b/src/components/mod_modal/mod_modal.scss @@ -24,7 +24,6 @@ } .mod-modal-panel { - overflow: hidden; transition: transform; transition-timing-function: ease-in-out; transition-duration: 300ms; diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.vue b/src/components/mod_modal/tabs/users_tab/users_tab.vue index 36cc67fd..46d69717 100644 --- a/src/components/mod_modal/tabs/users_tab/users_tab.vue +++ b/src/components/mod_modal/tabs/users_tab/users_tab.vue @@ -21,7 +21,7 @@ -

{{ $t('user_card.admin_menu.delete_user_confirmation') }}

+

{{ $t('user_card.admin_menu.delete_user_data_and_deactivate_confirmation') }}