Merge branch 'feature/add-links' into 'develop'

Add links to user's profile page and to user's account in Pleroma

See merge request pleroma/admin-fe!136
This commit is contained in:
Angelina Filippova 2020-06-11 20:23:15 +00:00
commit d8299972b5
9 changed files with 185 additions and 68 deletions

View file

@ -9,6 +9,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- Create `/statuses/:id` route that shows single status - Create `/statuses/:id` route that shows single status
- Add link to the user's account in Pleroma on the user's profile page
- On Reports page add links to reported account and the author of the report
- In Notes add link to the note author's profile page
- In Moderation log add link to the actor's profile page
### Changed ### Changed

View file

@ -5,7 +5,11 @@
<div class="status-account-container"> <div class="status-account-container">
<div class="status-account"> <div class="status-account">
<el-checkbox v-if="showCheckbox" class="status-checkbox" @change="handleStatusSelection(account)"/> <el-checkbox v-if="showCheckbox" class="status-checkbox" @change="handleStatusSelection(account)"/>
<router-link v-if="propertyExists(account, 'id')" :to="{ name: 'UsersShow', params: { id: account.id }}" @click.native.stop> <router-link
v-if="propertyExists(account, 'id')"
:to="{ name: 'UsersShow', params: { id: account.id }}"
class="router-link"
@click.native.stop>
<div class="status-card-header"> <div class="status-card-header">
<img v-if="propertyExists(account, 'avatar')" :src="account.avatar" class="status-avatar-img"> <img v-if="propertyExists(account, 'avatar')" :src="account.avatar" class="status-avatar-img">
<span v-if="propertyExists(account, 'nickname')" class="status-account-name">{{ account.nickname }}</span> <span v-if="propertyExists(account, 'nickname')" class="status-account-name">{{ account.nickname }}</span>
@ -100,7 +104,7 @@
<div class="status-footer"> <div class="status-footer">
<span class="status-created-at">{{ parseTimestamp(status.created_at) }}</span> <span class="status-created-at">{{ parseTimestamp(status.created_at) }}</span>
<a v-if="status.url" :href="status.url" target="_blank" class="account" @click.stop> <a v-if="status.url" :href="status.url" target="_blank" class="account" @click.stop>
Open status in instance {{ $t('statuses.openStatusInInstance') }}
<i class="el-icon-top-right"/> <i class="el-icon-top-right"/>
</a> </a>
</div> </div>
@ -264,6 +268,9 @@ export default {
width: 100%; width: 100%;
} }
} }
.router-link {
text-decoration: none;
}
.show-more-button { .show-more-button {
margin-left: 5px; margin-left: 5px;
} }

View file

@ -254,7 +254,8 @@ export default {
direct: 'Direct', direct: 'Direct',
private: 'Private', private: 'Private',
public: 'Public', public: 'Public',
unlisted: 'Unlisted' unlisted: 'Unlisted',
openStatusInInstance: 'Open status in instance'
}, },
userProfile: { userProfile: {
tags: 'Tags', tags: 'Tags',
@ -270,6 +271,7 @@ export default {
status: 'Status', status: 'Status',
deactivated: 'Deactivated', deactivated: 'Deactivated',
noStatuses: 'No statuses to show', noStatuses: 'No statuses to show',
openAccountInInstance: 'Open account in instance',
securitySettings: { securitySettings: {
email: 'Email', email: 'Email',
password: 'Password', password: 'Password',

View file

@ -0,0 +1,46 @@
<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>{{ logEntryMessage }}</span>
</span>
</template>
<script>
export default {
name: 'LogEntryMessage',
props: {
actor: {
type: Object,
required: true
},
message: {
type: String,
required: true
}
},
computed: {
logEntryMessage() {
return this.message.split(this.actor.nickname)[1]
}
},
methods: {
propertyExists(account, property) {
return account[property]
}
}
}
</script>
<style rel='stylesheet/scss' lang='scss'>
.router-link {
text-decoration: none;
}
</style>

View file

@ -43,7 +43,8 @@
v-for="(logEntry, index) in log" v-for="(logEntry, index) in log"
:key="index" :key="index"
:timestamp="normalizeTimestamp(logEntry.time)"> :timestamp="normalizeTimestamp(logEntry.time)">
{{ logEntry.message }} <log-entry-message v-if="propertyExists(logEntry.data.actor, 'nickname')" :actor="logEntry.data.actor" :message="logEntry.message"/>
<span v-else>{{ logEntry.message }}</span>
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
<div class="pagination"> <div class="pagination">
@ -64,9 +65,10 @@ import moment from 'moment'
import _ from 'lodash' import _ from 'lodash'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import RebootButton from '@/components/RebootButton' import RebootButton from '@/components/RebootButton'
import LogEntryMessage from './LogEntryMessage'
export default { export default {
components: { RebootButton }, components: { RebootButton, LogEntryMessage },
data() { data() {
return { return {
dateRange: '', dateRange: '',
@ -114,9 +116,6 @@ export default {
this.$store.dispatch('FetchAdmins') this.$store.dispatch('FetchAdmins')
}, },
methods: { methods: {
normalizeTimestamp(timestamp) {
return moment(timestamp * 1000).format('YYYY-MM-DD HH:mm')
},
fetchLogWithFilters() { fetchLogWithFilters() {
const filters = _.omitBy({ const filters = _.omitBy({
start_date: this.dateRange ? this.dateRange[0].toISOString() : null, start_date: this.dateRange ? this.dateRange[0].toISOString() : null,
@ -127,6 +126,12 @@ export default {
}, val => val === '' || val === null) }, val => val === '' || val === null)
this.$store.dispatch('FetchModerationLog', filters) this.$store.dispatch('FetchModerationLog', filters)
},
normalizeTimestamp(timestamp) {
return moment(timestamp * 1000).format('YYYY-MM-DD HH:mm')
},
propertyExists(account, property) {
return account[property]
} }
} }
} }

View file

@ -2,17 +2,25 @@
<el-card class="note-card"> <el-card class="note-card">
<div slot="header"> <div slot="header">
<div class="note-header"> <div class="note-header">
<router-link
v-if="propertyExists(note.user, 'id')"
:to="{ name: 'UsersShow', params: { id: note.user.id }}"
class="router-link">
<div class="note-actor"> <div class="note-actor">
<img v-if="propertyExists(note.user, 'avatar')" :src="note.user.avatar" class="note-avatar-img"> <img
v-if="propertyExists(note.user, 'avatar')"
:src="note.user.avatar"
alt="avatar"
class="note-avatar-img">
<span v-if="propertyExists(note.user, 'nickname')" class="note-actor-name">{{ note.user.nickname }}</span> <span v-if="propertyExists(note.user, 'nickname')" class="note-actor-name">{{ note.user.nickname }}</span>
<span v-else class="note-actor-name deactivated">({{ $t('users.invalidNickname') }})</span>
</div> </div>
<div> </router-link>
<el-button size="mini" @click.native="handleNoteDeletion(note.id, report.id)"> <el-button size="mini" @click.native="handleNoteDeletion(note.id, report.id)">
{{ $t('reports.deleteNote') }} {{ $t('reports.deleteNote') }}
</el-button> </el-button>
</div> </div>
</div> </div>
</div>
<div class="note-body"> <div class="note-body">
<span class="note-content" v-html="note.content"/> <span class="note-content" v-html="note.content"/>
{{ parseTimestamp(note.created_at) }} {{ parseTimestamp(note.created_at) }}
@ -68,6 +76,9 @@ export default {
a { a {
text-decoration: underline; text-decoration: underline;
} }
.deactivated {
color: gray;
}
.el-icon-arrow-right { .el-icon-arrow-right {
margin-right: 6px; margin-right: 6px;
} }
@ -108,6 +119,9 @@ export default {
font-size: 15px; font-size: 15px;
font-weight: 500; font-weight: 500;
} }
.router-link {
text-decoration: none;
}
@media only screen and (max-width:480px) { @media only screen and (max-width:480px) {
.el-card__header { .el-card__header {

View file

@ -27,23 +27,28 @@
<moderate-user-dropdown v-if="propertyExists(report.account, 'nickname')" :account="report.account"/> <moderate-user-dropdown v-if="propertyExists(report.account, 'nickname')" :account="report.account"/>
</div> </div>
</div> </div>
<div>
<el-divider class="divider"/> <el-divider class="divider"/>
<div class="report-account-container">
<span class="report-row-key">{{ $t('reports.account') }}:</span> <span class="report-row-key">{{ $t('reports.account') }}:</span>
<div class="report-account">
<router-link
v-if="propertyExists(report.account, 'id')"
:to="{ name: 'UsersShow', params: { id: report.account.id }}"
class="router-link">
<img <img
v-if="propertyExists(report.account, 'avatar')" v-if="propertyExists(report.account, 'avatar')"
:src="report.account.avatar" :src="report.account.avatar"
alt="avatar" alt="avatar"
class="avatar-img"> class="avatar-img">
<a v-if="propertyExists(report.account, 'url', 'nickname')" :href="report.account.url" target="_blank" class="account"> <span v-if="propertyExists(report.account, 'nickname')" class="report-account-name">{{ report.account.nickname }}</span>
<span class="report-account-name">{{ report.account.nickname }}</span>
</a>
<span v-else>
<span v-if="propertyExists(report.account, 'nickname')" class="report-account-name">
{{ report.account.nickname }}
</span>
<span v-else class="report-account-name deactivated">({{ $t('users.invalidNickname') }})</span> <span v-else class="report-account-name deactivated">({{ $t('users.invalidNickname') }})</span>
</span> </router-link>
<span v-else class="report-account-name deactivated">({{ $t('users.invalidNickname') }})</span>
<a v-if="propertyExists(report.account, 'url')" :href="report.account.url" target="_blank" class="account">
{{ $t('userProfile.openAccountInInstance') }}
<i class="el-icon-top-right"/>
</a>
</div>
</div> </div>
<div v-if="report.content && report.content.length > 0"> <div v-if="report.content && report.content.length > 0">
<el-divider class="divider"/> <el-divider class="divider"/>
@ -51,25 +56,30 @@
<span>{{ report.content }}</span> <span>{{ report.content }}</span>
</span> </span>
</div> </div>
<div :style="showStatuses(report.statuses) ? '' : 'margin-bottom:15px'">
<el-divider class="divider"/> <el-divider class="divider"/>
<div :style="showStatuses(report.statuses) ? '' : 'margin-bottom:15px'" class="report-account-container">
<span class="report-row-key">{{ $t('reports.actor') }}:</span> <span class="report-row-key">{{ $t('reports.actor') }}:</span>
<div class="report-account">
<router-link
v-if="propertyExists(report.actor, 'id')"
:to="{ name: 'UsersShow', params: { id: report.actor.id }}"
class="router-link">
<img <img
v-if="propertyExists(report.actor, 'avatar')" v-if="propertyExists(report.actor, 'avatar')"
:src="report.actor.avatar" :src="report.actor.avatar"
alt="avatar" alt="avatar"
class="avatar-img"> class="avatar-img">
<a v-if="propertyExists(report.actor, 'url', 'nickname')" :href="report.actor.url" target="_blank" class="account"> <span v-if="propertyExists(report.actor, 'nickname')" class="report-account-name">{{ report.actor.nickname }}</span>
<span class="report-account-name">{{ report.actor.nickname }}</span>
</a>
<span v-else>
<span v-if="propertyExists(report.actor, 'nickname')" class="report-account-name">
{{ report.actor.nickname }}
</span>
<span v-else class="report-account-name deactivated">({{ $t('users.invalidNickname') }})</span> <span v-else class="report-account-name deactivated">({{ $t('users.invalidNickname') }})</span>
</span> </router-link>
<span v-else class="report-account-name deactivated">({{ $t('users.invalidNickname') }})</span>
<a v-if="propertyExists(report.actor, 'url')" :href="report.actor.url" target="_blank" class="account">
{{ $t('userProfile.openAccountInInstance') }}
<i class="el-icon-top-right"/>
</a>
</div> </div>
<div v-if="showStatuses(report.statuses)" class="statuses"> </div>
<div v-if="showStatuses(report.statuses)" class="reported-statuses">
<el-collapse> <el-collapse>
<el-collapse-item :title="getStatusesTitle(report.statuses)"> <el-collapse-item :title="getStatusesTitle(report.statuses)">
<div v-for="status in report.statuses" :key="status.id"> <div v-for="status in report.statuses" :key="status.id">
@ -192,14 +202,22 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
h4 {
margin: 0;
height: 17px;
}
.account { .account {
line-height: 26px;
font-size: 13px;
color: #606266;
}
.account:hover {
text-decoration: underline; text-decoration: underline;
} }
.avatar-img { .avatar-img {
vertical-align: bottom; vertical-align: bottom;
width: 15px; width: 15px;
height: 15px; height: 15px;
margin-left: 5px;
} }
.divider { .divider {
margin: 15px 0; margin: 15px 0;
@ -231,18 +249,6 @@ export default {
padding: 10px 5px 10px 10px; padding: 10px 5px 10px 10px;
cursor: pointer; cursor: pointer;
} }
h4 {
margin: 0;
height: 17px;
}
.report {
.report-header-container {
display: flex;
justify-content: space-between;
align-items: baseline;
height: 40px;
}
}
.id { .id {
color: gray; color: gray;
margin-top: 6px; margin-top: 6px;
@ -269,6 +275,24 @@ export default {
font-style: italic; font-style: italic;
color: gray; color: gray;
} }
.report {
.report-header-container {
display: flex;
justify-content: space-between;
align-items: baseline;
height: 40px;
}
}
.report-account {
display: flex;
align-items: baseline;
justify-content: space-between;
flex-grow: 2;
}
.report-account-container {
display: flex;
align-items: baseline;
}
.report-account-name { .report-account-name {
font-size: 15px; font-size: 15px;
font-weight: 500; font-weight: 500;
@ -276,9 +300,7 @@ export default {
.report-row-key { .report-row-key {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
} padding-right: 5px;
.report-row-key {
font-size: 14px;
} }
.report-title { .report-title {
margin: 0; margin: 0;
@ -298,7 +320,10 @@ export default {
margin: 30px 45px 45px 19px; margin: 30px 45px 45px 19px;
padding: 0px; padding: 0px;
} }
.statuses { .router-link {
text-decoration: none;
}
.reported-statuses {
margin-top: 15px; margin-top: 15px;
} }
.submit-button { .submit-button {

View file

@ -2,15 +2,18 @@
<div v-if="!loading" class="status-show-container"> <div v-if="!loading" class="status-show-container">
<header v-if="isDesktop || isTablet" class="user-page-header"> <header v-if="isDesktop || isTablet" class="user-page-header">
<div class="avatar-name-container"> <div class="avatar-name-container">
<router-link v-if="propertyExists(user, 'id')" :to="{ name: 'UsersShow', params: { id: user.id }}"> <router-link
v-if="propertyExists(user, 'id')"
:to="{ name: 'UsersShow', params: { id: user.id }}"
class="router-link">
<div class="avatar-name-header"> <div class="avatar-name-header">
<el-avatar v-if="propertyExists(user, 'avatar')" :src="user.avatar" size="large" /> <el-avatar v-if="propertyExists(user, 'avatar')" :src="user.avatar" size="large" />
<h1 v-if="propertyExists(user, 'nickname')">{{ user.nickname }}</h1> <h1 v-if="propertyExists(user, 'nickname')">{{ user.nickname }}</h1>
<h1 v-else class="invalid">({{ $t('users.invalidNickname') }})</h1> <h1 v-else class="invalid">({{ $t('users.invalidNickname') }})</h1>
</div> </div>
</router-link> </router-link>
<a v-if="propertyExists(user, 'url')" :href="user.url" target="_blank" class="account"> <a v-if="propertyExists(user, 'url')" :href="user.url" target="_blank">
<i class="el-icon-top-right" title="Open user in instance"/> <i :title="$t('userProfile.openAccountInInstance')" class="el-icon-top-right"/>
</a> </a>
</div> </div>
<div class="left-header-container"> <div class="left-header-container">
@ -173,6 +176,9 @@ export default {
.reset-password-link { .reset-password-link {
text-decoration: underline; text-decoration: underline;
} }
.router-link {
text-decoration: none;
}
.status-container { .status-container {
margin: 0 15px 0 20px; margin: 0 15px 0 20px;
} }

View file

@ -5,6 +5,9 @@
<el-avatar v-if="propertyExists(user, 'avatar')" :src="user.avatar" size="large" /> <el-avatar v-if="propertyExists(user, 'avatar')" :src="user.avatar" size="large" />
<h1 v-if="propertyExists(user, 'nickname')">{{ user.nickname }}</h1> <h1 v-if="propertyExists(user, 'nickname')">{{ user.nickname }}</h1>
<h1 v-else class="invalid">({{ $t('users.invalidNickname') }})</h1> <h1 v-else class="invalid">({{ $t('users.invalidNickname') }})</h1>
<a v-if="propertyExists(user, 'url')" :href="user.url" target="_blank">
<i :title="$t('userProfile.openAccountInInstance')" class="el-icon-top-right"/>
</a>
</div> </div>
<div class="left-header-container"> <div class="left-header-container">
<moderation-dropdown <moderation-dropdown
@ -207,6 +210,11 @@ table {
.avatar-name-container { .avatar-name-container {
display: flex; display: flex;
align-items: center; align-items: center;
.el-icon-top-right {
font-size: 2em;
line-height: 36px;
color: #606266;
}
} }
.invalid { .invalid {
color: gray; color: gray;