diff --git a/src/api/__mocks__/reports.js b/src/api/__mocks__/reports.js index 36fc20088ae4eb347dea11e4903f30e98b1e2ce3..5c6fe3a1265d0a1031f89fb36138a7567ffa7860 100644 --- a/src/api/__mocks__/reports.js +++ b/src/api/__mocks__/reports.js @@ -1,14 +1,14 @@ const reports = [ - { created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame', tags: [] }, actor: { acct: 'admin' }, state: 'open', id: '2', content: 'This is a report', statuses: [] }, - { created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool', tags: [] }, actor: { acct: 'admin2' }, state: 'resolved', id: '1', content: 'Please block this user', statuses: [] }, - { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '3', content: '', statuses: [] }, - { created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame', tags: [] }, actor: { acct: 'admin' }, state: 'open', id: '5', content: 'This is a report', statuses: [] }, - { created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool', tags: [] }, actor: { acct: 'admin2' }, state: 'resolved', id: '7', content: 'Please block this user', statuses: [ + { created_at: '2019-05-21T21:35:33.000Z', account: { display_name: 'Benjamin Fame', tags: [] }, actor: {}, state: 'open', id: '2', content: 'This is a report', statuses: [] }, + { created_at: '2019-05-20T22:45:33.000Z', account: { display_name: 'Alice Pool', tags: [] }, actor: {}, state: 'resolved', id: '1', content: 'Please block this user', statuses: [] }, + { created_at: '2019-05-18T13:01:33.000Z', account: { display_name: 'Nick Keys', tags: [] }, actor: {}, state: 'closed', id: '3', content: '', statuses: [] }, + { created_at: '2019-05-21T21:35:33.000Z', account: { display_name: 'Benjamin Fame', tags: [] }, actor: {}, state: 'open', id: '5', content: 'This is a report', statuses: [] }, + { created_at: '2019-05-20T22:45:33.000Z', account: { display_name: 'Alice Pool', tags: [] }, actor: {}, state: 'resolved', id: '7', content: 'Please block this user', statuses: [ { account: { display_name: 'Alice Pool', avatar: '' }, visibility: 'public', sensitive: false, id: '11', content: 'Hey!', url: '', created_at: '2019-05-10T21:35:33.000Z' }, { account: { display_name: 'Alice Pool', avatar: '' }, visibility: 'unlisted', sensitive: true, id: '10', content: 'Bye!', url: '', created_at: '2019-05-10T21:00:33.000Z' } ] }, - { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '6', content: '', statuses: [] }, - { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '4', content: '', statuses: [] } + { created_at: '2019-05-18T13:01:33.000Z', account: { display_name: 'Nick Keys', tags: [] }, actor: {}, state: 'closed', id: '6', content: '', statuses: [] }, + { created_at: '2019-05-18T13:01:33.000Z', account: { display_name: 'Nick Keys', tags: [] }, actor: {}, state: 'closed', id: '4', content: '', statuses: [] } ] export async function fetchReports(filter, page, pageSize, authHost, token) { diff --git a/src/components/Status/index.vue b/src/components/Status/index.vue index 50fbcfb0bfcffae95ec803a6252f79b281671802..90058332e38f51d691884c76b40c2a4590c8af28 100644 --- a/src/components/Status/index.vue +++ b/src/components/Status/index.vue @@ -5,13 +5,17 @@ <div class="status-header"> <div class="status-account-container"> <div class="status-account"> - <el-checkbox v-if="showCheckbox" class="status-checkbox" @change="handleStatusSelection(status.account)"/> - <img :src="status.account.avatar" class="status-avatar-img"> - <h3 class="status-account-name">{{ status.account.display_name }}</h3> + <el-checkbox v-if="showCheckbox" class="status-checkbox" @change="handleStatusSelection(account)"/> + <img :src="account.avatar" class="status-avatar-img"> + <a v-if="!account.deactivated" :href="account.url" target="_blank" class="account"> + <h3 class="status-account-name">{{ account.display_name }}</h3> + </a> + <span v-else> + <h3 class="status-account-name">{{ account.display_name }}</h3> + <h3 class="status-account-name deactivated"> (deactivated)</h3> + </span> </div> - <a :href="status.account.url" target="_blank" class="account"> - @{{ status.account.acct }} - </a> + </div> <div class="status-actions"> <el-tag v-if="status.sensitive" type="warning" size="large">{{ $t('reports.sensitive') }}</el-tag> @@ -121,6 +125,11 @@ import moment from 'moment' export default { name: 'Status', props: { + account: { + type: Object, + required: false, + default: () => { return {} } + }, fetchStatusesByInstance: { type: Boolean, required: false, diff --git a/src/lang/en.js b/src/lang/en.js index 74891c59b9b09c99a30c52781b46e908c4021a23..74eaa909ded3a401c31cc19004f103b4116d73d4 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -293,6 +293,7 @@ export default { }, reports: { reports: 'Reports', + report: 'Report', reply: 'Reply', from: 'From', showNotes: 'Show notes', @@ -332,7 +333,8 @@ export default { statusDeleted: 'This status has been deleted', leaveNote: 'Leave a note', postNote: 'Send', - deleteNote: 'Delete' + deleteNote: 'Delete', + notFound: 'account not found' }, reportsFilter: { inputPlaceholder: 'Select filter', diff --git a/src/views/reports/components/ModerateUserDropdown.vue b/src/views/reports/components/ModerateUserDropdown.vue index 2d3689991e97590f1e4eff62553337d9033e4a98..fdae9c1814426343c33a5e33f71f6f8494152e46 100644 --- a/src/views/reports/components/ModerateUserDropdown.vue +++ b/src/views/reports/components/ModerateUserDropdown.vue @@ -1,6 +1,6 @@ <template> <el-dropdown trigger="click"> - <el-button plain size="small" icon="el-icon-files">{{ $t('reports.moderateUser') }} + <el-button :disabled="!account.id" plain size="small" icon="el-icon-files">{{ $t('reports.moderateUser') }} <i class="el-icon-arrow-down el-icon--right"/> </el-button> <el-dropdown-menu slot="dropdown"> @@ -16,42 +16,42 @@ </el-dropdown-item> <el-dropdown-item :divided="true" - :class="{ 'active-tag': account.tags.includes('force_nsfw') }" + :class="{ 'active-tag': tags.includes('force_nsfw') }" @click.native="toggleTag(account, 'force_nsfw')"> {{ $t('users.forceNsfw') }} - <i v-if="account.tags.includes('force_nsfw')" class="el-icon-check"/> + <i v-if="tags.includes('force_nsfw')" class="el-icon-check"/> </el-dropdown-item> <el-dropdown-item - :class="{ 'active-tag': account.tags.includes('strip_media') }" + :class="{ 'active-tag': tags.includes('strip_media') }" @click.native="toggleTag(account, 'strip_media')"> {{ $t('users.stripMedia') }} - <i v-if="account.tags.includes('strip_media')" class="el-icon-check"/> + <i v-if="tags.includes('strip_media')" class="el-icon-check"/> </el-dropdown-item> <el-dropdown-item - :class="{ 'active-tag': account.tags.includes('force_unlisted') }" + :class="{ 'active-tag': tags.includes('force_unlisted') }" @click.native="toggleTag(account, 'force_unlisted')"> {{ $t('users.forceUnlisted') }} - <i v-if="account.tags.includes('force_unlisted')" class="el-icon-check"/> + <i v-if="tags.includes('force_unlisted')" class="el-icon-check"/> </el-dropdown-item> <el-dropdown-item - :class="{ 'active-tag': account.tags.includes('sandbox') }" + :class="{ 'active-tag': tags.includes('sandbox') }" @click.native="toggleTag(account, 'sandbox')"> {{ $t('users.sandbox') }} - <i v-if="account.tags.includes('sandbox')" class="el-icon-check"/> + <i v-if="tags.includes('sandbox')" class="el-icon-check"/> </el-dropdown-item> <el-dropdown-item v-if="account.local" - :class="{ 'active-tag': account.tags.includes('disable_remote_subscription') }" + :class="{ 'active-tag': tags.includes('disable_remote_subscription') }" @click.native="toggleTag(account, 'disable_remote_subscription')"> {{ $t('users.disableRemoteSubscription') }} - <i v-if="account.tags.includes('disable_remote_subscription')" class="el-icon-check"/> + <i v-if="tags.includes('disable_remote_subscription')" class="el-icon-check"/> </el-dropdown-item> <el-dropdown-item v-if="account.local" - :class="{ 'active-tag': account.tags.includes('disable_any_subscription') }" + :class="{ 'active-tag': tags.includes('disable_any_subscription') }" @click.native="toggleTag(account, 'disable_any_subscription')"> {{ $t('users.disableAnySubscription') }} - <i v-if="account.tags.includes('disable_any_subscription')" class="el-icon-check"/> + <i v-if="tags.includes('disable_any_subscription')" class="el-icon-check"/> </el-dropdown-item> </el-dropdown-menu> </el-dropdown> @@ -66,6 +66,11 @@ export default { required: true } }, + computed: { + tags() { + return this.account.tags || [] + } + }, methods: { handleDeactivation({ nickname }) { this.$store.dispatch('ToggleUserActivation', nickname) diff --git a/src/views/reports/components/NoteCard.vue b/src/views/reports/components/NoteCard.vue index 379e752bdc8cf2523b3a8a95f91f36d1aae6a34e..79637f1601ae5b97df1d7de2ec570e95921b911e 100644 --- a/src/views/reports/components/NoteCard.vue +++ b/src/views/reports/components/NoteCard.vue @@ -8,7 +8,7 @@ <h3 class="note-actor-name">{{ note.user.display_name }}</h3> </div> <a :href="note.user.url" target="_blank"> - @{{ note.user.acct }} + @{{ note.user.display_name }} </a> </div> <div> diff --git a/src/views/reports/components/Report.vue b/src/views/reports/components/Report.vue index f2361e6c79c04d89dc4471d43c867853a2bd0a2e..565b3cb0c91007ed31918db66076ae0da868076d 100644 --- a/src/views/reports/components/Report.vue +++ b/src/views/reports/components/Report.vue @@ -10,7 +10,8 @@ <el-card class="report"> <div class="report-header-container"> <div class="title-container"> - <h3 class="report-title">{{ $t('reports.reportOn') }} {{ report.account.display_name }}</h3> + <h3 v-if="accountExists(report.account, 'display_name')" class="report-title">{{ $t('reports.reportOn') }} {{ report.account.display_name }}</h3> + <h3 v-else class="report-title">{{ $t('reports.report') }}</h3> <h5 class="id">{{ $t('reports.id') }}: {{ report.id }}</h5> </div> <div> @@ -29,15 +30,22 @@ <div> <el-divider class="divider"/> <span class="report-row-key">{{ $t('reports.account') }}:</span> - <img - :src="report.account.avatar" - alt="avatar" - class="avatar-img"> - <a :href="report.account.url" target="_blank" class="account"> - <span>{{ report.account.acct }}</span> - </a> + <span v-if="accountExists(report.account, 'avatar') && accountExists(report.account, 'display_name')"> + <img + :src="report.account.avatar" + alt="avatar" + class="avatar-img"> + <a v-if="!report.account.deactivated" :href="report.account.url" target="_blank" class="account"> + <span>{{ report.account.display_name }}</span> + </a> + <span v-else> + {{ report.account.display_name }} + <span class="deactivated"> (deactivated)</span> + </span> + </span> + <span v-else class="deactivated">({{ $t('reports.notFound') }})</span> </div> - <div v-if="report.content.length > 0"> + <div v-if="report.content && report.content.length > 0"> <el-divider class="divider"/> <span class="report-row-key">{{ $t('reports.content') }}: <span>{{ report.content }}</span> @@ -46,19 +54,22 @@ <div :style="showStatuses(report.statuses) ? '' : 'margin-bottom:15px'"> <el-divider class="divider"/> <span class="report-row-key">{{ $t('reports.actor') }}:</span> - <img - :src="report.actor.avatar" - alt="avatar" - class="avatar-img"> - <a :href="report.actor.url" target="_blank" class="account"> - <span>{{ report.actor.acct }}</span> - </a> + <span v-if="accountExists(report.actor, 'avatar') && accountExists(report.actor, 'display_name')"> + <img + :src="report.actor.avatar" + alt="avatar" + class="avatar-img"> + <a :href="report.actor.url" target="_blank" class="account"> + <span>{{ report.actor.display_name }}</span> + </a> + </span> + <span v-else class="deactivated">({{ $t('reports.notFound') }})</span> </div> <div v-if="showStatuses(report.statuses)" class="statuses"> <el-collapse> <el-collapse-item :title="getStatusesTitle(report.statuses)"> <div v-for="status in report.statuses" :key="status.id"> - <status :status="status" :show-checkbox="false" :page="currentPage"/> + <status :status="status" :account="status.account.display_name ? status.account : report.account" :show-checkbox="false" :page="currentPage"/> </div> </el-collapse-item> </el-collapse> @@ -131,6 +142,9 @@ export default { } }, methods: { + accountExists(account, key) { + return account[key] + }, changeReportState(state, id) { this.$store.dispatch('ChangeReportState', [{ state, id }]) }, @@ -147,7 +161,7 @@ export default { return 'primary' } }, - getStatusesTitle(statuses) { + getStatusesTitle(statuses = []) { return `Reported statuses: ${statuses.length} item(s)` }, getNotesTitle(notes = []) { @@ -163,7 +177,7 @@ export default { parseTimestamp(timestamp) { return moment(timestamp).format('L HH:mm') }, - showStatuses(statuses) { + showStatuses(statuses = []) { return statuses.length > 0 } } @@ -183,6 +197,9 @@ export default { .divider { margin: 15px 0; } + .deactivated { + color: gray; + } .el-card__body { padding: 17px; } diff --git a/src/views/reports/components/ReportCard.vue b/src/views/reports/components/ReportCard.vue deleted file mode 100644 index 430b58bbf309e4aab74d53a77bc3f2ab5dad85a3..0000000000000000000000000000000000000000 --- a/src/views/reports/components/ReportCard.vue +++ /dev/null @@ -1,127 +0,0 @@ -<template> - <div> - <el-card v-for="report in reports" :key="report.id" class="report-card"> - <div slot="header"> - <div class="report-header"> - <div class="report-actor-container"> - <div class="report-actor"> - <img :src="report.actor.avatar" class="report-avatar-img"> - <h3 class="report-actor-name">{{ report.actor.display_name }}</h3> - </div> - <a :href="report.actor.url" target="_blank"> - @{{ report.actor.acct }} - </a> - </div> - <div> - <el-tag :type="getStateType(report.state)" size="large" class="report-tag">{{ capitalizeFirstLetter(report.state) }}</el-tag> - <el-dropdown trigger="click"> - <el-button plain size="small" icon="el-icon-edit">{{ $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> - <el-dropdown-item v-if="report.state !== 'closed'" @click.native="changeReportState('closed', report.id)">{{ $t('reports.close') }}</el-dropdown-item> - </el-dropdown-menu> - </el-dropdown> - </div> - </div> - </div> - <div class="report-body"> - <span class="report-content" v-html="report.content"/> - {{ parseTimestamp(report.created_at) }} - </div> - </el-card> - </div> -</template> - -<script> -import moment from 'moment' - -export default { - name: 'Statuses', - props: { - reports: { - type: Array, - required: true - } - }, - methods: { - capitalizeFirstLetter(str) { - return str.charAt(0).toUpperCase() + str.slice(1) - }, - changeReportState(state, id) { - this.$store.dispatch('ChangeReportState', [{ state, id }]) - }, - getStateType(state) { - switch (state) { - case 'closed': - return 'info' - case 'resolved': - return 'success' - default: - return 'primary' - } - }, - parseTimestamp(timestamp) { - return moment(timestamp).format('YYYY-MM-DD HH:mm') - } - } -} -</script> - -<style rel='stylesheet/scss' lang='scss'> - a { - text-decoration: underline; - } - .el-icon-arrow-right { - margin-right: 6px; - } - .report-header { - display: flex; - justify-content: space-between; - align-items: baseline; - height: 40px; - } - .report-actor { - display: flex; - align-items: center; - } - .report-actor-name { - margin: 0; - height: 22px; - } - .report-avatar-img { - width: 15px; - height: 15px; - margin-right: 5px; - } - .report-body { - display: flex; - flex-direction: column; - } - .report-card { - margin-bottom: 15px; - } - .report-content { - font-size: 15px; - } - .report-header { - display: flex; - justify-content: space-between; - } - - @media only screen and (max-width:480px) { - .el-card__header { - padding: 10px 17px; - } - .report-header { - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: flex-start; - height: auto; - } - .report-tag { - margin: 3px 0 6px; - } - } -</style> diff --git a/src/views/statuses/index.vue b/src/views/statuses/index.vue index 0b5a377867fbb4e20608fb027521533feb6a3c5a..0d17316f0e6450e5ab886394ab7d857f1fb59c10 100644 --- a/src/views/statuses/index.vue +++ b/src/views/statuses/index.vue @@ -45,6 +45,7 @@ <div v-for="status in statuses" :key="status.id" class="status-container"> <status :status="status" + :account="status.account" :show-checkbox="isDesktop" :fetch-statuses-by-instance="true" @status-selection="handleStatusSelection" /> diff --git a/src/views/users/show.vue b/src/views/users/show.vue index ca1b3d95778a58a4e099fc80aa1ce7e8a76b48d3..a4ae844a965617bf1528bb789bb5ddec413d0ce4 100644 --- a/src/views/users/show.vue +++ b/src/views/users/show.vue @@ -107,7 +107,7 @@ </el-checkbox> <el-timeline v-if="!statusesLoading" class="statuses"> <el-timeline-item v-for="status in statuses" :key="status.id"> - <status :status="status" :show-checkbox="false" :user-id="user.id" :godmode="showPrivate"/> + <status :status="status" :account="status.account" :show-checkbox="false" :user-id="user.id" :godmode="showPrivate"/> </el-timeline-item> <p v-if="statuses.length === 0" class="no-statuses">{{ $t('userProfile.noStatuses') }}</p> </el-timeline>