diff --git a/CHANGELOG.md b/CHANGELOG.md index bb1790ccfa85e0ba3e7d0986f5b7b03260701ab6..d7a6de166906b833b7d4faba38693782ebccca03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,12 +14,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Add Unconfimed filter for Users table - Filter users by actor type: Person, Bot or Application - Add ability to configure Media Preview Proxy, User Backup and Websocket based federation settings - +- Mobile and Tablet UI for Single Report show page ### Changed - Hide Tag actions on Users tab if MRF TagPolicy is disabled. Add ability to enable TagPolicy from Moderation menu - Move `:restrict_unauthenticated` settings from Authentication tab to Instance tab - Replace regular inputs with textareas for setting welcome messages in the Settings section +- Update rendering Moderation Log Messages so that all usernames are links to the pages of the corresponding users in Admin-FE ### Fixed diff --git a/src/store/modules/reports.js b/src/store/modules/reports.js index c42fa8947d9c6cc765158b84ce3bcdc6948f4b95..2589daa43380a326c88a3ee59e8f843e7590bc36 100644 --- a/src/store/modules/reports.js +++ b/src/store/modules/reports.js @@ -12,6 +12,7 @@ const reports = { currentPage: 1, fetchedReports: [], loading: true, + loadingSingleReport: true, openReportsCount: 0, pageSize: 50, singleReport: {}, @@ -42,6 +43,9 @@ const reports = { }, SET_SINGLE_REPORT: (state, report) => { state.singleReport = report + }, + SET_SINGLE_REPORT_LOADING: (state, status) => { + state.loadingSingleReport = status } }, actions: { @@ -162,11 +166,11 @@ const reports = { commit('SET_LOADING', false) }, async FetchSingleReport({ commit, getters }, id) { - commit('SET_LOADING', true) + commit('SET_SINGLE_REPORT_LOADING', true) const { data } = await fetchSingleReport(id, getters.authHost, getters.token) commit('SET_SINGLE_REPORT', data) - commit('SET_LOADING', false) + commit('SET_SINGLE_REPORT_LOADING', false) }, async FetchOpenReportsCount({ commit, getters, state }) { commit('SET_LOADING', true) diff --git a/src/views/moderation_log/LogEntryMessage.vue b/src/views/moderation_log/LogEntryMessage.vue deleted file mode 100644 index d19ada814893c5d526d735ba0a41b3e606c58483..0000000000000000000000000000000000000000 --- a/src/views/moderation_log/LogEntryMessage.vue +++ /dev/null @@ -1,65 +0,0 @@ -<template> - <span> - <router-link - v-if="propertyExists(actor, 'id')" - :to="{ name: 'UsersShow', params: { id: actor.id }}" - class="router-link"> - <span v-if="propertyExists(actor, 'nickname')" style="font-weight: 600"> - @{{ actor.nickname }} - </span> - </router-link> - <span v-if="subject.type === 'report' && propertyExists(subject, 'id')"> - {{ logEntryMessageWithoutId[0] }} - <router-link - :to="{ name: 'ReportsShow', params: { id: subject.id }}" - class="router-link"> - <span style="font-weight: 600">#{{ subject.id }}</span> - </router-link> - {{ logEntryMessageWithoutId[1] }} - </span> - <span v-else>{{ logEntryMessage }}</span> - </span> -</template> - -<script> - -export default { - name: 'LogEntryMessage', - props: { - actor: { - type: Object, - required: true - }, - message: { - type: String, - required: true - }, - subject: { - type: [Object, Array], - required: false, - default: function() { - return {} - } - } - }, - computed: { - logEntryMessage() { - return this.actor.nickname ? this.message.split(this.actor.nickname)[1] : this.message - }, - logEntryMessageWithoutId() { - return this.logEntryMessage.split(`#${this.subject.id}`) - } - }, - methods: { - propertyExists(account, property) { - return account[property] - } - } -} -</script> - -<style rel='stylesheet/scss' lang='scss'> - .router-link { - text-decoration: none; - } -</style> diff --git a/src/views/moderation_log/ReportLink.vue b/src/views/moderation_log/ReportLink.vue new file mode 100644 index 0000000000000000000000000000000000000000..bfbd210a04e179b817bbb089ec2ceab0f6974236 --- /dev/null +++ b/src/views/moderation_log/ReportLink.vue @@ -0,0 +1,20 @@ +<template> + <router-link + :to="{ name: 'ReportsShow', params: { id }}" + class="router-link"> + <span style="font-weight: 600">#{{ id }}</span> + </router-link> +</template> + +<script> + +export default { + name: 'UserLink', + props: { + id: { + type: String, + required: true + } + } +} +</script> diff --git a/src/views/moderation_log/UserLink.vue b/src/views/moderation_log/UserLink.vue new file mode 100644 index 0000000000000000000000000000000000000000..77ab82a4aa734a0beedd79237af82fd67753d19a --- /dev/null +++ b/src/views/moderation_log/UserLink.vue @@ -0,0 +1,20 @@ +<template> + <router-link + :to="{ name: 'UsersShow', params: { id: actor }}" + class="router-link"> + <span style="font-weight: 600">@{{ actor }}</span> + </router-link> +</template> + +<script> + +export default { + name: 'UserLink', + props: { + actor: { + type: String, + required: true + } + } +} +</script> diff --git a/src/views/moderation_log/index.vue b/src/views/moderation_log/index.vue index 283bf4d298e71cdb2c2b6a6cc1b22698b36f6965..c8c350c4e4e16fe004f1fa801e79d7cbf5478f21 100644 --- a/src/views/moderation_log/index.vue +++ b/src/views/moderation_log/index.vue @@ -43,8 +43,7 @@ v-for="(logEntry, index) in log" :key="index" :timestamp="normalizeTimestamp(logEntry.time)"> - <log-entry-message v-if="propertyExists(logEntry.data.actor, 'nickname')" :actor="logEntry.data.actor" :message="logEntry.message" :subject="logEntry.data.subject"/> - <span v-else>{{ logEntry.message }}</span> + <component :is="processedMessage(logEntry)"/> </el-timeline-item> </el-timeline> <div class="pagination"> @@ -65,10 +64,14 @@ import moment from 'moment' import _ from 'lodash' import debounce from 'lodash.debounce' import RebootButton from '@/components/RebootButton' -import LogEntryMessage from './LogEntryMessage' +import ReportLink from './ReportLink' +import UserLink from './UserLink' +import Vue from 'vue' +Vue.component('user-link', UserLink) +Vue.component('report-link', ReportLink) export default { - components: { RebootButton, LogEntryMessage }, + components: { RebootButton }, data() { return { dateRange: '', @@ -130,6 +133,24 @@ export default { normalizeTimestamp(timestamp) { return moment(timestamp * 1000).format('YYYY-MM-DD HH:mm') }, + processedMessage(logEntry) { + const html = [...logEntry.message.matchAll(/\@(?<nickname>([\w-]+))/g)].map(res => res.groups.nickname) + .reduce((acc, nickname) => { + return acc.replace(`@${nickname}`, `<user-link actor="${nickname}"/>`) + }, logEntry.message) + if (this.propertyExists(logEntry.data, 'subject') && logEntry.data.subject.type === 'report') { + const updatedHtml = [...html.matchAll(/\#(?<reportId>([\w]+))/g)].map(res => res.groups.reportId) + .reduce((acc, id) => { + return acc.replace(`#${id}`, `<report-link id="${id}"/>`) + }, html) + return { + template: '<div>' + updatedHtml + '</div>' + } + } + return { + template: '<div>' + html + '</div>' + } + }, propertyExists(account, property) { return account[property] } @@ -173,6 +194,9 @@ h1 { margin: 0; width: 145px; } +.router-link { + text-decoration: none; +} .search-container { text-align: right; } diff --git a/src/views/reports/components/ModerateUserDropdown.vue b/src/views/reports/components/ModerateUserDropdown.vue index 3d5618f11ed9685227eed3bd09ce87a1f9d0bc21..6c93ca829eceb740b52f8986fe7703e3d34b7c10 100644 --- a/src/views/reports/components/ModerateUserDropdown.vue +++ b/src/views/reports/components/ModerateUserDropdown.vue @@ -1,6 +1,6 @@ <template> <el-dropdown :hide-on-click="false" trigger="click"> - <el-button :disabled="!account.id" :size="renderedFrom === 'showPage' ? 'medium' : 'small'" plain icon="el-icon-files"> + <el-button :disabled="!account.id" :size="renderedFrom === 'showPage' && !isMobile ? 'medium' : 'small'" plain icon="el-icon-files"> {{ $t('reports.moderateUser') }} <i class="el-icon-arrow-down el-icon--right"/> </el-button> @@ -87,6 +87,9 @@ export default { } }, computed: { + isMobile() { + return this.$store.state.app.device === 'mobile' + }, tagPolicyEnabled() { return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy') }, diff --git a/src/views/reports/components/ReportContent.vue b/src/views/reports/components/ReportContent.vue index 030fc93e59707a509924e80cbf73f8c5b2e73d56..639e1cc7ff21ceba636492aa13b91f2403086eeb 100644 --- a/src/views/reports/components/ReportContent.vue +++ b/src/views/reports/components/ReportContent.vue @@ -179,4 +179,15 @@ export default { .router-link { text-decoration: none; } + @media only screen and (max-width:480px) { + .divider { + margin: 10px 0; + } + .el-card__body { + padding: 13px; + } + .report-account { + flex-direction: column; + } + } </style> diff --git a/src/views/reports/show.vue b/src/views/reports/show.vue index 5f30f37630fdfd2146845d772241372d75ba6598..b62efe3b7a5192cbf18f27d2c5ebd9b63f12ef06 100644 --- a/src/views/reports/show.vue +++ b/src/views/reports/show.vue @@ -4,7 +4,11 @@ <div class="report-page-header"> <div v-if="propertyExists(report.account, 'nickname')" class="avatar-name-container"> <h1 >{{ $t('reports.reportOn') }}</h1> - <el-avatar v-if="propertyExists(report.account, 'avatar')" :src="report.account.avatar" size="large" class="report-page-avatar"/> + <el-avatar + v-if="propertyExists(report.account, 'avatar')" + :src="report.account.avatar" + :size="isMobile ? 'small' : 'large'" + class="report-page-avatar"/> <h1>{{ report.account.nickname }}</h1> <a v-if="propertyExists(report.account, 'url')" :href="report.account.url" target="_blank"> <i :title="$t('userProfile.openAccountInInstance')" class="el-icon-top-right"/> @@ -12,10 +16,16 @@ </div> <h1 v-else>{{ $t('reports.report') }}</h1> </div> - <div> + <div class="report-actions-container"> <el-tag :type="getStateType(report.state)" class="report-tag">{{ capitalizeFirstLetter(report.state) }}</el-tag> <el-dropdown trigger="click"> - <el-button plain icon="el-icon-edit" class="report-actions-button">{{ $t('reports.changeState') }}<i class="el-icon-arrow-down el-icon--right"/></el-button> + <el-button + :size="isMobile ? 'small' : 'medium'" + plain + icon="el-icon-edit" + class="report-actions-button"> + {{ $t('reports.changeState') }}<i class="el-icon-arrow-down el-icon--right"/> + </el-button> <el-dropdown-menu slot="dropdown"> <el-dropdown-item v-if="report.state !== 'resolved'" @click.native="changeReportState('resolved', report.id)">{{ $t('reports.resolve') }}</el-dropdown-item> <el-dropdown-item v-if="report.state !== 'open'" @click.native="changeReportState('open', report.id)">{{ $t('reports.reopen') }}</el-dropdown-item> @@ -31,9 +41,11 @@ </div> </header> <h4 v-if="propertyExists(report.account, 'id')" class="id">{{ $t('reports.id') }}: {{ report.id }}</h4> - <el-card class="report"> - <report-content :report="report"/> - </el-card> + <div class="report-card-container"> + <el-card class="report"> + <report-content :report="report"/> + </el-card> + </div> </div> </template> @@ -46,8 +58,11 @@ export default { name: 'ReportsShow', components: { ModerateUserDropdown, RebootButton, ReportContent }, computed: { + isMobile() { + return this.$store.state.app.device === 'mobile' + }, loading() { - return this.$store.state.reports.loading + return this.$store.state.reports.loadingSingleReport }, report() { return this.$store.state.reports.singleReport @@ -94,11 +109,19 @@ export default { margin: 0 15px 22px 15px; } .report { - width: 1000px; + max-width: 1000px; margin: auto; } .report-actions-button { - margin: 3px 0 6px; + margin: 0 5px; + } + .report-actions-container { + display: flex; + flex-wrap: wrap; + } + .report-card-container { + margin: auto; + padding: 0 15px; } .report-page-header { display: flex; @@ -139,4 +162,38 @@ export default { font-size: 14px; } } +@media only screen and (max-width:801px) { + .report-show-page-container { + .id { + margin: 7px 15px 15px 15px; + } + .report-actions-button { + margin: 0 3px 6px; + } + .report-page-header-container { + flex-direction: column; + align-items: flex-start; + } + .report-page-header { + h1 { + font-size: 24px; + } + .avatar-name-container { + .el-icon-top-right { + font-size: 24px; + } + } + .report-page-avatar { + margin: 0 5px 0 9px; + } + } + } +} +@media only screen and (max-width:480px) { + .report-tag { + height: 32px; + line-height: 32px; + font-size: 14px; + } +} </style>