Add reports tab to moderation modal
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
This commit is contained in:
parent
b490ade544
commit
405a60d249
12 changed files with 583 additions and 78 deletions
|
@ -2,18 +2,6 @@
|
||||||
.mod-modal {
|
.mod-modal {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.setting-list,
|
|
||||||
.option-list {
|
|
||||||
list-style-type: none;
|
|
||||||
padding-left: 2em;
|
|
||||||
li {
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
.suboptions {
|
|
||||||
margin-top: 0.3em
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.peek {
|
&.peek {
|
||||||
.mod-modal-panel {
|
.mod-modal-panel {
|
||||||
/* Explanation:
|
/* Explanation:
|
||||||
|
@ -49,15 +37,8 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
>.panel-body {
|
.panel-body {
|
||||||
height: 100%;
|
height: inherit;
|
||||||
overflow-y: hidden;
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
min-height: 2em;
|
|
||||||
min-width: 10em;
|
|
||||||
padding: 0 2em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||||
|
|
||||||
import ReportsTab from './tabs/reports_tab.vue'
|
import ReportsTab from './tabs/reports_tab/reports_tab.vue'
|
||||||
import StatusesTab from './tabs/statuses_tab.vue'
|
// import StatusesTab from './tabs/statuses_tab.vue'
|
||||||
import UsersTab from './tabs/users_tab.vue'
|
// import UsersTab from './tabs/users_tab.vue'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
@ -21,9 +21,9 @@ const ModModalContent = {
|
||||||
components: {
|
components: {
|
||||||
TabSwitcher,
|
TabSwitcher,
|
||||||
|
|
||||||
ReportsTab,
|
ReportsTab
|
||||||
StatusesTab,
|
// StatusesTab,
|
||||||
UsersTab
|
// UsersTab
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
open () {
|
open () {
|
||||||
|
|
|
@ -2,53 +2,20 @@
|
||||||
.mod_tab-switcher {
|
.mod_tab-switcher {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.setting-item {
|
.content {
|
||||||
border-bottom: 2px solid var(--fg, $fallback--fg);
|
|
||||||
margin: 1em 1em 1.4em;
|
margin: 1em 1em 1.4em;
|
||||||
padding-bottom: 1.4em;
|
|
||||||
|
|
||||||
> div,
|
> div {
|
||||||
> label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
margin-bottom: .5em;
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-multiple {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.option-list {
|
|
||||||
margin: 0;
|
|
||||||
padding-left: .5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
padding-bottom: 0;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
min-width: 10em;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unavailable,
|
|
||||||
.unavailable svg {
|
|
||||||
color: var(--cRed, $fallback--cRed);
|
|
||||||
color: $fallback--cRed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.number-input {
|
|
||||||
max-width: 6em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,26 +7,26 @@
|
||||||
:body-scroll-lock="bodyLock"
|
:body-scroll-lock="bodyLock"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
:label="$t('moderation.reports')"
|
:label="$t('moderation.reports.reports')"
|
||||||
icon="flag"
|
icon="flag"
|
||||||
data-tab-name="reports"
|
data-tab-name="reports"
|
||||||
>
|
>
|
||||||
<ReportsTab />
|
<ReportsTab />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<!-- <div -->
|
||||||
:label="$t('moderation.users')"
|
<!-- :label="$t('moderation.users')" -->
|
||||||
icon="users"
|
<!-- icon="users" -->
|
||||||
data-tab-name="users"
|
<!-- data-tab-name="users" -->
|
||||||
>
|
<!-- > -->
|
||||||
<UsersTab />
|
<!-- <UsersTab /> -->
|
||||||
</div>
|
<!-- </div> -->
|
||||||
<div
|
<!-- <div -->
|
||||||
:label="$t('moderation.statuses')"
|
<!-- :label="$t('moderation.statuses')" -->
|
||||||
icon="message"
|
<!-- icon="message" -->
|
||||||
data-tab-name="statuses"
|
<!-- data-tab-name="statuses" -->
|
||||||
>
|
<!-- > -->
|
||||||
<StatusesTab />
|
<!-- <StatusesTab /> -->
|
||||||
</div>
|
<!-- </div> -->
|
||||||
</tab-switcher>
|
</tab-switcher>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
124
src/components/mod_modal/tabs/reports_tab/report_card.js
Normal file
124
src/components/mod_modal/tabs/reports_tab/report_card.js
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
|
import Status from 'src/components/status/status.vue'
|
||||||
|
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
||||||
|
import ReportNote from './report_note.vue'
|
||||||
|
|
||||||
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
import {
|
||||||
|
faChevronDown,
|
||||||
|
faChevronUp
|
||||||
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
library.add(
|
||||||
|
faChevronDown,
|
||||||
|
faChevronUp
|
||||||
|
)
|
||||||
|
|
||||||
|
const FORCE_NSFW = 'mrf_tag:media-force-nsfw'
|
||||||
|
const STRIP_MEDIA = 'mrf_tag:media-strip'
|
||||||
|
const FORCE_UNLISTED = 'mrf_tag:force-unlisted'
|
||||||
|
const SANDBOX = 'mrf_tag:sandbox'
|
||||||
|
|
||||||
|
const ReportCard = {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
hidden: true,
|
||||||
|
statusesHidden: true,
|
||||||
|
notesHidden: true,
|
||||||
|
note: null,
|
||||||
|
tags: {
|
||||||
|
FORCE_NSFW,
|
||||||
|
STRIP_MEDIA,
|
||||||
|
FORCE_UNLISTED,
|
||||||
|
SANDBOX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: [
|
||||||
|
'account',
|
||||||
|
'actor',
|
||||||
|
'content',
|
||||||
|
'id',
|
||||||
|
'notes',
|
||||||
|
'state',
|
||||||
|
'statuses'
|
||||||
|
],
|
||||||
|
components: {
|
||||||
|
ReportNote,
|
||||||
|
Popover,
|
||||||
|
Status,
|
||||||
|
UserAvatar
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.$store.dispatch('fetchUser', this.account.id)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isOpen () {
|
||||||
|
return this.state === 'open'
|
||||||
|
},
|
||||||
|
tagPolicyEnabled () {
|
||||||
|
return this.$store.state.instance.federationPolicy.mrf_policies.includes('TagPolicy')
|
||||||
|
},
|
||||||
|
user () {
|
||||||
|
return this.$store.getters.findUser(this.account.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleHidden () {
|
||||||
|
this.hidden = !this.hidden
|
||||||
|
},
|
||||||
|
decode (content) {
|
||||||
|
content = content.replaceAll('<br/>', '\n')
|
||||||
|
const textarea = document.createElement('textarea')
|
||||||
|
textarea.innerHTML = content
|
||||||
|
return textarea.value
|
||||||
|
},
|
||||||
|
updateReportState (state) {
|
||||||
|
this.$store.dispatch('updateReportStates', { reports: [{ id: this.id, state }] })
|
||||||
|
},
|
||||||
|
toggleNotes () {
|
||||||
|
this.notesHidden = !this.notesHidden
|
||||||
|
},
|
||||||
|
addNoteToReport () {
|
||||||
|
if (this.note.length > 0) {
|
||||||
|
this.$store.dispatch('addNoteToReport', { id: this.id, note: this.note })
|
||||||
|
this.note = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggleStatuses () {
|
||||||
|
this.statusesHidden = !this.statusesHidden
|
||||||
|
},
|
||||||
|
hasTag (tag) {
|
||||||
|
return this.user.tags.includes(tag)
|
||||||
|
},
|
||||||
|
toggleTag (tag) {
|
||||||
|
if (this.hasTag(tag)) {
|
||||||
|
this.$store.state.api.backendInteractor.untagUser({ user: this.user, tag }).then(response => {
|
||||||
|
if (!response.ok) { return }
|
||||||
|
this.$store.commit('untagUser', { user: this.user, tag })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$store.state.api.backendInteractor.tagUser({ user: this.user, tag }).then(response => {
|
||||||
|
if (!response.ok) { return }
|
||||||
|
this.$store.commit('tagUser', { user: this.user, tag })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggleActivationStatus () {
|
||||||
|
this.$store.dispatch('toggleActivationStatus', { user: this.user })
|
||||||
|
},
|
||||||
|
deleteUser () {
|
||||||
|
this.$store.state.backendInteractor.deleteUser({ user: this.user })
|
||||||
|
.then(e => {
|
||||||
|
this.$store.dispatch('markStatusesAsDeleted', status => this.user.id === status.user.id)
|
||||||
|
const isProfile = this.$route.name === 'external-user-profile' || this.$route.name === 'user-profile'
|
||||||
|
const isTargetUser = this.$route.params.name === this.user.name || this.$route.params.id === this.user.id
|
||||||
|
if (isProfile && isTargetUser) {
|
||||||
|
window.history.back()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReportCard
|
202
src/components/mod_modal/tabs/reports_tab/report_card.vue
Normal file
202
src/components/mod_modal/tabs/reports_tab/report_card.vue
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
<template>
|
||||||
|
<div class="report-card panel">
|
||||||
|
<div
|
||||||
|
class="panel-heading"
|
||||||
|
@click="toggleHidden"
|
||||||
|
>
|
||||||
|
<h4>{{ $t('moderation.reports.report') + ' ' + this.account.screen_name }}</h4>
|
||||||
|
<button
|
||||||
|
v-if="isOpen"
|
||||||
|
class="button-default"
|
||||||
|
@click.stop="updateReportState('closed')"
|
||||||
|
>
|
||||||
|
{{ $t('moderation.reports.close') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="isOpen"
|
||||||
|
class="button-default"
|
||||||
|
@click.stop="updateReportState('resolved')"
|
||||||
|
>
|
||||||
|
{{ $t('moderation.reports.resolve') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else
|
||||||
|
class="button-default"
|
||||||
|
@click.stop="updateReportState('open')"
|
||||||
|
>
|
||||||
|
{{ $t('moderation.reports.reopen') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="!hidden"
|
||||||
|
class="panel-body report-body"
|
||||||
|
>
|
||||||
|
<div class="report-content">
|
||||||
|
<div v-if="content">
|
||||||
|
{{ decode(content) }}
|
||||||
|
</div>
|
||||||
|
<i v-else class="faint">
|
||||||
|
{{ $t('moderation.reports.no_content') }}
|
||||||
|
</i>
|
||||||
|
<div class="report-author">
|
||||||
|
<UserAvatar
|
||||||
|
class="small-avatar"
|
||||||
|
:user="actor"
|
||||||
|
/>
|
||||||
|
{{ this.actor.screen_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="dropdown"
|
||||||
|
v-if="!hidden && this.statuses.length > 0"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="button button-unstyled dropdown-header"
|
||||||
|
@click="toggleStatuses"
|
||||||
|
>
|
||||||
|
{{ this.statuses.length + ' ' + $t('moderation.reports.statuses') }}
|
||||||
|
<FAIcon
|
||||||
|
class="timelines-chevron"
|
||||||
|
fixed-width
|
||||||
|
:icon="statusesHidden ? 'chevron-down' : 'chevron-up'"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<div v-if="!statusesHidden">
|
||||||
|
<Status
|
||||||
|
v-for="status in statuses"
|
||||||
|
:key="status.id"
|
||||||
|
:collapsable="false"
|
||||||
|
:expandable="false"
|
||||||
|
:compact="false"
|
||||||
|
:statusoid="status"
|
||||||
|
:no-heading="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="dropdown"
|
||||||
|
v-if="!hidden && this.notes.length > 0"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="button button-unstyled dropdown-header"
|
||||||
|
@click="toggleNotes"
|
||||||
|
>
|
||||||
|
{{ this.notes.length + ' ' + $t('moderation.reports.notes') }}
|
||||||
|
<FAIcon
|
||||||
|
class="timelines-chevron"
|
||||||
|
fixed-width
|
||||||
|
:icon="notesHidden ? 'chevron-down' : 'chevron-up'"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<div v-if="!notesHidden">
|
||||||
|
<ReportNote
|
||||||
|
v-for="note in notes"
|
||||||
|
:key="note.id"
|
||||||
|
:report_id="id"
|
||||||
|
v-bind="note"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="report-add-note">
|
||||||
|
<textarea
|
||||||
|
rows="1"
|
||||||
|
cols="1"
|
||||||
|
v-model.trim="note"
|
||||||
|
:placeholder="$t('moderation.reports.note_placeholder')"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
@click.stop="addNoteToReport"
|
||||||
|
>
|
||||||
|
{{ $t('moderation.reports.add_note') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="!hidden"
|
||||||
|
class="panel-footer"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
@click.stop="toggleActivationStatus"
|
||||||
|
>
|
||||||
|
{{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
@click.stop="deleteUser"
|
||||||
|
>
|
||||||
|
{{ $t('user_card.admin_menu.delete_account') }}
|
||||||
|
</button>
|
||||||
|
<Popover
|
||||||
|
trigger="click"
|
||||||
|
placement="top"
|
||||||
|
:offset="{ y: 5 }"
|
||||||
|
remove-padding
|
||||||
|
>
|
||||||
|
<template v-slot:trigger>
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
:disabled="!tagPolicyEnabled"
|
||||||
|
:title="tagPolicyEnabled ? '' : $t('moderation.reports.account.tag_policy_notice')"
|
||||||
|
>
|
||||||
|
<span>{{ $t("moderation.reports.tags") }}</span>
|
||||||
|
{{ ' ' }}
|
||||||
|
<FAIcon
|
||||||
|
icon="chevron-down"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<template v-slot:content="{close}">
|
||||||
|
<div
|
||||||
|
class="dropdown-menu"
|
||||||
|
:disabled="!tagPolicyEnabled"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
|
@click.prevent="toggleTag(tags.FORCE_NSFW)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="menu-checkbox"
|
||||||
|
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }"
|
||||||
|
/>
|
||||||
|
{{ $t('user_card.admin_menu.force_nsfw') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
|
@click.prevent="toggleTag(tags.STRIP_MEDIA)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="menu-checkbox"
|
||||||
|
:class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }"
|
||||||
|
/>
|
||||||
|
{{ $t('user_card.admin_menu.strip_media') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
|
@click.prevent="toggleTag(tags.FORCE_UNLISTED)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="menu-checkbox"
|
||||||
|
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }"
|
||||||
|
/>
|
||||||
|
{{ $t('user_card.admin_menu.force_unlisted') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
|
@click.prevent="toggleTag(tags.SANDBOX)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="menu-checkbox"
|
||||||
|
:class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }"
|
||||||
|
/>
|
||||||
|
{{ $t('user_card.admin_menu.sandbox') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./report_card.js"></script>
|
37
src/components/mod_modal/tabs/reports_tab/report_note.js
Normal file
37
src/components/mod_modal/tabs/reports_tab/report_note.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue'
|
||||||
|
import Timeago from 'src/components/timeago/timeago.vue'
|
||||||
|
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
|
||||||
|
|
||||||
|
const ReportNote = {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
showingDeleteDialog: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: [
|
||||||
|
'content',
|
||||||
|
'created_at',
|
||||||
|
'user',
|
||||||
|
'report_id',
|
||||||
|
'id'
|
||||||
|
],
|
||||||
|
components: {
|
||||||
|
ConfirmModal,
|
||||||
|
Timeago,
|
||||||
|
UserAvatar
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
deleteNoteFromReport () {
|
||||||
|
this.$store.dispatch('deleteNoteFromReport', { id: this.report_id, note: this.id })
|
||||||
|
this.showingDeleteDialog = false
|
||||||
|
},
|
||||||
|
showDeleteDialog () {
|
||||||
|
this.showingDeleteDialog = true
|
||||||
|
},
|
||||||
|
hideDeleteDialog () {
|
||||||
|
this.showingDeleteDialog = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReportNote
|
43
src/components/mod_modal/tabs/reports_tab/report_note.vue
Normal file
43
src/components/mod_modal/tabs/reports_tab/report_note.vue
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<template>
|
||||||
|
<div class="report-note">
|
||||||
|
<div class="note-header">
|
||||||
|
<div class="note-author">
|
||||||
|
<UserAvatar
|
||||||
|
class="small-avatar"
|
||||||
|
:user="user"
|
||||||
|
/>
|
||||||
|
{{ this.user.screen_name }}
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<Timeago
|
||||||
|
class="faint"
|
||||||
|
:time="created_at"
|
||||||
|
:auto-update="60"
|
||||||
|
:long-format="true"
|
||||||
|
:with-direction="true"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
@click.stop="showDeleteDialog"
|
||||||
|
>
|
||||||
|
{{ $t('moderation.reports.delete_note') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="note-content">
|
||||||
|
{{ content }}
|
||||||
|
</div>
|
||||||
|
<confirm-modal
|
||||||
|
v-if="showingDeleteDialog"
|
||||||
|
:title="$t('moderation.reports.delete_note_title')"
|
||||||
|
:confirm-text="$t('moderation.reports.delete_note_accept')"
|
||||||
|
:cancel-text="$t('moderation.reports.delete_note_cancel')"
|
||||||
|
@accepted="deleteNoteFromReport"
|
||||||
|
@cancelled="hideDeleteDialog"
|
||||||
|
>
|
||||||
|
{{ $t('moderation.reports.delete_note_confirm') }}
|
||||||
|
</confirm-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./report_note.js"></script>
|
29
src/components/mod_modal/tabs/reports_tab/reports_tab.js
Normal file
29
src/components/mod_modal/tabs/reports_tab/reports_tab.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { filter } from 'lodash'
|
||||||
|
|
||||||
|
import ReportCard from './report_card.vue'
|
||||||
|
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||||
|
|
||||||
|
const ReportsTab = {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
showClosed: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.$store.dispatch('getReports')
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Checkbox,
|
||||||
|
ReportCard
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
reports () {
|
||||||
|
return this.$store.state.reports.reports
|
||||||
|
},
|
||||||
|
openReports () {
|
||||||
|
return filter(this.reports, { state: 'open' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReportsTab
|
83
src/components/mod_modal/tabs/reports_tab/reports_tab.scss
Normal file
83
src/components/mod_modal/tabs/reports_tab/reports_tab.scss
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
@import '../../../../_variables.scss';
|
||||||
|
.report-card {
|
||||||
|
.report-body {
|
||||||
|
& > * {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :not(:last-child) {
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
border-bottom-color: var(--border, #222);
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-content {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-author {
|
||||||
|
padding-top: 0.5em;
|
||||||
|
}
|
||||||
|
.small-avatar {
|
||||||
|
height: 25px;
|
||||||
|
width: 25px;
|
||||||
|
padding-right: 0.4em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.dropdown-header {
|
||||||
|
padding: 1em;
|
||||||
|
color: var(--link, $fallback--link);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--selectedMenu, $fallback--lightBg);
|
||||||
|
color: var(--selectedMenuText, $fallback--link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-note {
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
.note-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-add-note {
|
||||||
|
textarea {
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
min-height: 2em;
|
||||||
|
min-width: 10em;
|
||||||
|
padding: 0 2em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-footer {
|
||||||
|
display: flex;
|
||||||
|
& > * {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reports-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
20
src/components/mod_modal/tabs/reports_tab/reports_tab.vue
Normal file
20
src/components/mod_modal/tabs/reports_tab/reports_tab.vue
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<template>
|
||||||
|
<div :label="$t('moderation.reports.reports')">
|
||||||
|
<div class="content">
|
||||||
|
<div class="reports-header">
|
||||||
|
<h2>{{ $t('moderation.reports.reports') }}</h2>
|
||||||
|
<Checkbox v-model="showClosed">
|
||||||
|
{{ $t('moderation.reports.show_closed') }}
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
<ReportCard
|
||||||
|
v-for="report in (showClosed ? reports : openReports)"
|
||||||
|
:key="report.id"
|
||||||
|
v-bind="report"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./reports_tab.js"></script>
|
||||||
|
<style src="./reports_tab.scss" lang="scss"></style>
|
|
@ -268,7 +268,26 @@
|
||||||
},
|
},
|
||||||
"moderation": {
|
"moderation": {
|
||||||
"moderation": "Moderation",
|
"moderation": "Moderation",
|
||||||
|
"reports": {
|
||||||
|
"add_note": "Add note",
|
||||||
|
"close": "Close",
|
||||||
|
"delete_note": "Delete",
|
||||||
|
"delete_note_accept": "Yes, delete it",
|
||||||
|
"delete_note_cancel": "No, keep it",
|
||||||
|
"delete_note_confirm": "Are you sure you want to delete this note?",
|
||||||
|
"delete_note_title": "Confirm deletion",
|
||||||
|
"no_content": "No description given",
|
||||||
|
"note_placeholder": "Leave a note...",
|
||||||
|
"notes": "notes",
|
||||||
|
"reopen": "Reopen",
|
||||||
|
"report": "Report on",
|
||||||
"reports": "Reports",
|
"reports": "Reports",
|
||||||
|
"resolve": "Resolve",
|
||||||
|
"show_closed": "Show closed",
|
||||||
|
"statuses": "statuses",
|
||||||
|
"tag_policy_notice": "Enable the TagPolicy MRF to set post restrictions",
|
||||||
|
"tags": "Set post restrictions"
|
||||||
|
},
|
||||||
"statuses": "Statuses",
|
"statuses": "Statuses",
|
||||||
"users": "Users"
|
"users": "Users"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue