forked from AkkomaGang/admin-fe
Merge branch 'feature/combine-reports-with-one-topic' into 'master'
Combine reports with one topic and add pagination See merge request pleroma/admin-fe!52
This commit is contained in:
commit
253fa33235
26 changed files with 1414 additions and 782 deletions
|
@ -11,18 +11,41 @@ const reports = [
|
||||||
{ 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: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '4', content: '', statuses: [] }
|
||||||
]
|
]
|
||||||
|
|
||||||
export async function fetchReports(limit, max_id, authHost, token) {
|
const groupedReports = [
|
||||||
const paginatedReports = max_id.length > 0 ? reports.slice(5) : reports.slice(0, 5)
|
{ account: { avatar: 'http://localhost:4000/images/avi.png', confirmation_pending: false, deactivated: false, display_name: 'leo', id: '9oG0YghgBi94EATI9I', local: true, nickname: 'leo', roles: { admin: false, moderator: false }, tags: [] },
|
||||||
return Promise.resolve({ data: { reports: paginatedReports }})
|
actors: [{ acct: 'admin', avatar: 'http://localhost:4000/images/avi.png', deactivated: false, display_name: 'admin', id: '9oFz4pTauG0cnJ581w', local: true, nickname: 'admin', roles: { admin: false, moderator: false }, tags: [], url: 'http://localhost:4000/users/admin', username: 'admin' }],
|
||||||
|
date: '2019-11-23T12:56:11.969772Z',
|
||||||
|
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: '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' }
|
||||||
|
] }
|
||||||
|
],
|
||||||
|
status: {
|
||||||
|
account: { acct: 'leo' },
|
||||||
|
content: 'At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis',
|
||||||
|
created_at: '2019-11-23T12:55:20.000Z',
|
||||||
|
id: '9pFoQO69piu7cUDnJg',
|
||||||
|
url: 'http://localhost:4000/notice/9pFoQO69piu7cUDnJg',
|
||||||
|
visibility: 'unlisted',
|
||||||
|
sensitive: true
|
||||||
|
},
|
||||||
|
status_deleted: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export async function fetchReports(filter, page, pageSize, authHost, token) {
|
||||||
|
return filter.length > 0
|
||||||
|
? Promise.resolve({ data: { reports: reports.filter(report => report.state === filter) }})
|
||||||
|
: Promise.resolve({ data: { reports }})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function filterReports(filter, limit, max_id, authHost, token) {
|
export async function fetchGroupedReports(authHost, token) {
|
||||||
const filteredReports = reports.filter(report => report.state === filter)
|
return Promise.resolve({ data: { reports: groupedReports }})
|
||||||
const paginatedReports = max_id.length > 0 ? filteredReports.slice(5) : filteredReports.slice(0, 5)
|
|
||||||
return Promise.resolve({ data: { reports: paginatedReports }})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function changeState(state, id, authHost, token) {
|
export async function changeState(reportsData, authHost, token) {
|
||||||
return Promise.resolve({ data: '' })
|
return Promise.resolve({ data: '' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
src/api/__mocks__/status.js
Normal file
7
src/api/__mocks__/status.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export async function changeStatusScope(id, sensitive, visibility, authHost, token) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteStatus(id, authHost, token) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
|
@ -2,48 +2,32 @@ import request from '@/utils/request'
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
import { baseName } from './utils'
|
import { baseName } from './utils'
|
||||||
|
|
||||||
export async function changeState(state, id, authHost, token) {
|
export async function changeState(reports, authHost, token) {
|
||||||
return await request({
|
return await request({
|
||||||
baseURL: baseName(authHost),
|
baseURL: baseName(authHost),
|
||||||
url: `/api/pleroma/admin/reports`,
|
url: `/api/pleroma/admin/reports`,
|
||||||
method: 'patch',
|
method: 'patch',
|
||||||
headers: authHeaders(token),
|
headers: authHeaders(token),
|
||||||
data: { reports: [{ id, state }] }
|
data: { reports }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function changeStatusScope(id, sensitive, visibility, authHost, token) {
|
export async function fetchReports(filter, page, pageSize, authHost, token) {
|
||||||
|
const url = filter.length > 0
|
||||||
|
? `/api/pleroma/admin/reports?state=${filter}&page=${page}&page_size=${pageSize}`
|
||||||
|
: `/api/pleroma/admin/reports?page=${page}&page_size=${pageSize}`
|
||||||
return await request({
|
return await request({
|
||||||
baseURL: baseName(authHost),
|
baseURL: baseName(authHost),
|
||||||
url: `/api/pleroma/admin/statuses/${id}`,
|
url,
|
||||||
method: 'put',
|
|
||||||
headers: authHeaders(token),
|
|
||||||
data: { sensitive, visibility }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteStatus(id, authHost, token) {
|
|
||||||
return await request({
|
|
||||||
baseURL: baseName(authHost),
|
|
||||||
url: `/api/pleroma/admin/statuses/${id}`,
|
|
||||||
method: 'delete',
|
|
||||||
headers: authHeaders(token)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function fetchReports(limit, max_id, authHost, token) {
|
|
||||||
return await request({
|
|
||||||
baseURL: baseName(authHost),
|
|
||||||
url: `/api/pleroma/admin/reports?limit=${limit}&max_id=${max_id}`,
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: authHeaders(token)
|
headers: authHeaders(token)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function filterReports(filter, limit, max_id, authHost, token) {
|
export async function fetchGroupedReports(authHost, token) {
|
||||||
return await request({
|
return await request({
|
||||||
baseURL: baseName(authHost),
|
baseURL: baseName(authHost),
|
||||||
url: `/api/pleroma/admin/reports?state=${filter}&limit=${limit}&max_id=${max_id}`,
|
url: `/api/pleroma/admin/grouped_reports`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: authHeaders(token)
|
headers: authHeaders(token)
|
||||||
})
|
})
|
||||||
|
|
24
src/api/status.js
Normal file
24
src/api/status.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
import { baseName } from './utils'
|
||||||
|
|
||||||
|
export async function changeStatusScope(id, sensitive, visibility, authHost, token) {
|
||||||
|
return await request({
|
||||||
|
baseURL: baseName(authHost),
|
||||||
|
url: `/api/pleroma/admin/statuses/${id}`,
|
||||||
|
method: 'put',
|
||||||
|
headers: authHeaders(token),
|
||||||
|
data: { sensitive, visibility }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteStatus(id, authHost, token) {
|
||||||
|
return await request({
|
||||||
|
baseURL: baseName(authHost),
|
||||||
|
url: `/api/pleroma/admin/statuses/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
headers: authHeaders(token)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}
|
|
@ -253,6 +253,7 @@ export default {
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
reports: 'Reports',
|
reports: 'Reports',
|
||||||
|
groupedReports: 'Grouped reports',
|
||||||
reply: 'Reply',
|
reply: 'Reply',
|
||||||
from: 'From',
|
from: 'From',
|
||||||
showNotes: 'Show notes',
|
showNotes: 'Show notes',
|
||||||
|
@ -264,19 +265,32 @@ export default {
|
||||||
deleteCompleted: 'Delete comleted',
|
deleteCompleted: 'Delete comleted',
|
||||||
deleteCanceled: 'Delete canceled',
|
deleteCanceled: 'Delete canceled',
|
||||||
noNotes: 'No notes to display',
|
noNotes: 'No notes to display',
|
||||||
changeState: 'Change report state',
|
changeState: "Change report's state",
|
||||||
|
changeAllReports: 'Change all reports',
|
||||||
changeScope: 'Change scope',
|
changeScope: 'Change scope',
|
||||||
moderateUser: 'Moderate user',
|
moderateUser: 'Moderate user',
|
||||||
resolve: 'Resolve',
|
resolve: 'Resolve',
|
||||||
reopen: 'Reopen',
|
reopen: 'Reopen',
|
||||||
close: 'Close',
|
close: 'Close',
|
||||||
|
resolveAll: 'Resolve all',
|
||||||
|
reopenAll: 'Reopen all',
|
||||||
|
closeAll: 'Close all',
|
||||||
addSensitive: 'Add Sensitive flag',
|
addSensitive: 'Add Sensitive flag',
|
||||||
removeSensitive: 'Remove Sensitive flag',
|
removeSensitive: 'Remove Sensitive flag',
|
||||||
public: 'Make status public',
|
public: 'Make status public',
|
||||||
private: 'Make status private',
|
private: 'Make status private',
|
||||||
unlisted: 'Make status unlisted',
|
unlisted: 'Make status unlisted',
|
||||||
sensitive: 'Sensitive',
|
sensitive: 'Sensitive',
|
||||||
deleteStatus: 'Delete status'
|
deleteStatus: 'Delete status',
|
||||||
|
reportOn: 'Report on',
|
||||||
|
reportsOn: 'Reports on',
|
||||||
|
id: 'ID',
|
||||||
|
account: 'Account',
|
||||||
|
actor: 'Actor',
|
||||||
|
actors: 'Actors',
|
||||||
|
content: 'Content',
|
||||||
|
reportedStatus: 'Reported status',
|
||||||
|
statusDeleted: 'This status has been deleted'
|
||||||
},
|
},
|
||||||
reportsFilter: {
|
reportsFilter: {
|
||||||
inputPlaceholder: 'Select filter',
|
inputPlaceholder: 'Select filter',
|
||||||
|
|
|
@ -8,6 +8,7 @@ import permission from './modules/permission'
|
||||||
import relays from './modules/relays'
|
import relays from './modules/relays'
|
||||||
import reports from './modules/reports'
|
import reports from './modules/reports'
|
||||||
import settings from './modules/settings'
|
import settings from './modules/settings'
|
||||||
|
import status from './modules/status'
|
||||||
import tagsView from './modules/tagsView'
|
import tagsView from './modules/tagsView'
|
||||||
import user from './modules/user'
|
import user from './modules/user'
|
||||||
import userProfile from './modules/userProfile'
|
import userProfile from './modules/userProfile'
|
||||||
|
@ -27,6 +28,7 @@ const store = new Vuex.Store({
|
||||||
relays,
|
relays,
|
||||||
reports,
|
reports,
|
||||||
settings,
|
settings,
|
||||||
|
status,
|
||||||
tagsView,
|
tagsView,
|
||||||
user,
|
user,
|
||||||
userProfile,
|
userProfile,
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import { changeState, changeStatusScope, deleteStatus, fetchReports, filterReports } from '@/api/reports'
|
import { changeState, fetchReports, fetchGroupedReports } from '@/api/reports'
|
||||||
|
|
||||||
const reports = {
|
const reports = {
|
||||||
state: {
|
state: {
|
||||||
fetchedReports: [],
|
fetchedReports: [],
|
||||||
idOfLastReport: '',
|
fetchedGroupedReports: [],
|
||||||
page_limit: 5,
|
totalReportsCount: 0,
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
groupReports: false,
|
||||||
stateFilter: '',
|
stateFilter: '',
|
||||||
loading: true
|
loading: true
|
||||||
},
|
},
|
||||||
|
@ -15,67 +18,67 @@ const reports = {
|
||||||
SET_LOADING: (state, status) => {
|
SET_LOADING: (state, status) => {
|
||||||
state.loading = status
|
state.loading = status
|
||||||
},
|
},
|
||||||
|
SET_PAGE: (state, page) => {
|
||||||
|
state.currentPage = page
|
||||||
|
},
|
||||||
SET_REPORTS: (state, reports) => {
|
SET_REPORTS: (state, reports) => {
|
||||||
state.fetchedReports = reports
|
state.fetchedReports = reports
|
||||||
},
|
},
|
||||||
|
SET_GROUPED_REPORTS: (state, reports) => {
|
||||||
|
state.fetchedGroupedReports = reports
|
||||||
|
},
|
||||||
|
SET_REPORTS_COUNT: (state, total) => {
|
||||||
|
state.totalReportsCount = total
|
||||||
|
},
|
||||||
SET_REPORTS_FILTER: (state, filter) => {
|
SET_REPORTS_FILTER: (state, filter) => {
|
||||||
state.stateFilter = filter
|
state.stateFilter = filter
|
||||||
|
},
|
||||||
|
SET_REPORTS_GROUPING: (state) => {
|
||||||
|
state.groupReports = !state.groupReports
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async ChangeReportState({ commit, getters, state }, { reportState, reportId }) {
|
async ChangeReportState({ commit, getters, state }, reportsData) {
|
||||||
changeState(reportState, reportId, getters.authHost, getters.token)
|
changeState(reportsData, getters.authHost, getters.token)
|
||||||
|
|
||||||
const updatedReports = state.fetchedReports.map(report => {
|
const updatedReports = state.fetchedReports.map(report => {
|
||||||
return report.id === reportId ? { ...report, state: reportState } : report
|
const updatedReportsIds = reportsData.map(({ id }) => id)
|
||||||
|
return updatedReportsIds.includes(report.id) ? { ...report, state: reportsData[0].state } : report
|
||||||
|
})
|
||||||
|
|
||||||
|
const updatedGroupedReports = state.fetchedGroupedReports.map(group => {
|
||||||
|
const updatedReportsIds = reportsData.map(({ id }) => id)
|
||||||
|
const updatedReports = group.reports.map(report => updatedReportsIds.includes(report.id) ? { ...report, state: reportsData[0].state } : report)
|
||||||
|
return { ...group, reports: updatedReports }
|
||||||
})
|
})
|
||||||
|
|
||||||
commit('SET_REPORTS', updatedReports)
|
commit('SET_REPORTS', updatedReports)
|
||||||
},
|
commit('SET_GROUPED_REPORTS', updatedGroupedReports)
|
||||||
async ChangeStatusScope({ commit, getters, state }, { statusId, isSensitive, visibility, reportId }) {
|
|
||||||
const { data } = await changeStatusScope(statusId, isSensitive, visibility, getters.authHost, getters.token)
|
|
||||||
const updatedReports = state.fetchedReports.map(report => {
|
|
||||||
if (report.id === reportId) {
|
|
||||||
const statuses = report.statuses.map(status => status.id === statusId ? data : status)
|
|
||||||
return { ...report, statuses }
|
|
||||||
} else {
|
|
||||||
return report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
commit('SET_REPORTS', updatedReports)
|
|
||||||
},
|
},
|
||||||
ClearFetchedReports({ commit }) {
|
ClearFetchedReports({ commit }) {
|
||||||
commit('SET_REPORTS', [])
|
commit('SET_REPORTS', [])
|
||||||
commit('SET_LAST_REPORT_ID', '')
|
|
||||||
},
|
},
|
||||||
async DeleteStatus({ commit, getters, state }, { statusId, reportId }) {
|
async FetchReports({ commit, getters, state }, page) {
|
||||||
deleteStatus(statusId, getters.authHost, getters.token)
|
|
||||||
const updatedReports = state.fetchedReports.map(report => {
|
|
||||||
if (report.id === reportId) {
|
|
||||||
const statuses = report.statuses.filter(status => status.id !== statusId)
|
|
||||||
return { ...report, statuses }
|
|
||||||
} else {
|
|
||||||
return report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
commit('SET_REPORTS', updatedReports)
|
|
||||||
},
|
|
||||||
async FetchReports({ commit, getters, state }) {
|
|
||||||
commit('SET_LOADING', true)
|
commit('SET_LOADING', true)
|
||||||
|
const { data } = await fetchReports(state.stateFilter, page, state.pageSize, getters.authHost, getters.token)
|
||||||
|
|
||||||
const response = state.stateFilter.length === 0
|
commit('SET_REPORTS', data.reports)
|
||||||
? await fetchReports(state.page_limit, state.idOfLastReport, getters.authHost, getters.token)
|
commit('SET_REPORTS_COUNT', data.total)
|
||||||
: await filterReports(state.stateFilter, state.page_limit, state.idOfLastReport, getters.authHost, getters.token)
|
commit('SET_PAGE', page)
|
||||||
|
commit('SET_LOADING', false)
|
||||||
|
},
|
||||||
|
async FetchGroupedReports({ commit, getters }) {
|
||||||
|
commit('SET_LOADING', true)
|
||||||
|
const { data } = await fetchGroupedReports(getters.authHost, getters.token)
|
||||||
|
|
||||||
const reports = state.fetchedReports.concat(response.data.reports)
|
commit('SET_GROUPED_REPORTS', data.reports)
|
||||||
const id = reports.length > 0 ? reports[reports.length - 1].id : state.idOfLastReport
|
|
||||||
|
|
||||||
commit('SET_REPORTS', reports)
|
|
||||||
commit('SET_LAST_REPORT_ID', id)
|
|
||||||
commit('SET_LOADING', false)
|
commit('SET_LOADING', false)
|
||||||
},
|
},
|
||||||
SetFilter({ commit }, filter) {
|
SetFilter({ commit }, filter) {
|
||||||
commit('SET_REPORTS_FILTER', filter)
|
commit('SET_REPORTS_FILTER', filter)
|
||||||
|
},
|
||||||
|
ToggleReportsGrouping({ commit }) {
|
||||||
|
commit('SET_REPORTS_GROUPING')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
28
src/store/modules/status.js
Normal file
28
src/store/modules/status.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { changeStatusScope, deleteStatus } from '@/api/status'
|
||||||
|
|
||||||
|
const status = {
|
||||||
|
actions: {
|
||||||
|
async ChangeStatusScope({ dispatch, getters }, { statusId, isSensitive, visibility, reportCurrentPage, userId, godmode }) {
|
||||||
|
await changeStatusScope(statusId, isSensitive, visibility, getters.authHost, getters.token)
|
||||||
|
if (reportCurrentPage !== 0) { // called from Reports
|
||||||
|
dispatch('FetchReports', reportCurrentPage)
|
||||||
|
} else if (userId.length > 0) { // called from User profile
|
||||||
|
dispatch('FetchUserStatuses', { userId, godmode })
|
||||||
|
} else { // called from GroupedReports
|
||||||
|
dispatch('FetchGroupedReports')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async DeleteStatus({ dispatch, getters }, { statusId, reportCurrentPage, userId, godmode }) {
|
||||||
|
await deleteStatus(statusId, getters.authHost, getters.token)
|
||||||
|
if (reportCurrentPage !== 0) {
|
||||||
|
dispatch('FetchReports', reportCurrentPage)
|
||||||
|
} else if (userId.length > 0) {
|
||||||
|
dispatch('FetchUserStatuses', { userId, godmode })
|
||||||
|
} else {
|
||||||
|
dispatch('FetchGroupedReports')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default status
|
|
@ -2,33 +2,42 @@ import { fetchUser, fetchUserStatuses } from '@/api/users'
|
||||||
|
|
||||||
const userProfile = {
|
const userProfile = {
|
||||||
state: {
|
state: {
|
||||||
|
statuses: [],
|
||||||
|
statusesLoading: true,
|
||||||
user: {},
|
user: {},
|
||||||
loading: true,
|
userProfileLoading: true
|
||||||
statuses: []
|
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
|
SET_STATUSES: (state, statuses) => {
|
||||||
|
state.statuses = statuses
|
||||||
|
},
|
||||||
|
SET_STATUSES_LOADING: (state, status) => {
|
||||||
|
state.statusesLoading = status
|
||||||
|
},
|
||||||
SET_USER: (state, user) => {
|
SET_USER: (state, user) => {
|
||||||
state.user = user
|
state.user = user
|
||||||
},
|
},
|
||||||
SET_LOADING: (state, status) => {
|
SET_USER_PROFILE_LOADING: (state, status) => {
|
||||||
state.loading = status
|
state.userProfileLoading = status
|
||||||
},
|
|
||||||
SET_STATUSES: (state, statuses) => {
|
|
||||||
state.statuses = statuses
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async FetchData({ commit, getters }, { id, godmode }) {
|
async FetchUserProfile({ commit, dispatch, getters }, { userId, godmode }) {
|
||||||
commit('SET_LOADING', true)
|
commit('SET_USER_PROFILE_LOADING', true)
|
||||||
|
|
||||||
const [userResponse, statusesResponse] = await Promise.all([
|
|
||||||
fetchUser(id, getters.authHost, getters.token),
|
|
||||||
fetchUserStatuses(id, getters.authHost, godmode, getters.token)
|
|
||||||
])
|
|
||||||
|
|
||||||
|
const userResponse = await fetchUser(userId, getters.authHost, getters.token)
|
||||||
commit('SET_USER', userResponse.data)
|
commit('SET_USER', userResponse.data)
|
||||||
commit('SET_STATUSES', statusesResponse.data)
|
commit('SET_USER_PROFILE_LOADING', false)
|
||||||
commit('SET_LOADING', false)
|
|
||||||
|
dispatch('FetchUserStatuses', { userId, godmode })
|
||||||
|
},
|
||||||
|
async FetchUserStatuses({ commit, getters }, { userId, godmode }) {
|
||||||
|
commit('SET_STATUSES_LOADING', true)
|
||||||
|
|
||||||
|
const statuses = await fetchUserStatuses(userId, getters.authHost, godmode, getters.token)
|
||||||
|
|
||||||
|
commit('SET_STATUSES', statuses.data)
|
||||||
|
commit('SET_STATUSES_LOADING', false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
143
src/views/reports/components/GroupedReport.vue
Normal file
143
src/views/reports/components/GroupedReport.vue
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
<template>
|
||||||
|
<el-timeline class="timeline">
|
||||||
|
<el-timeline-item
|
||||||
|
v-for="groupedReport in groupedReports"
|
||||||
|
:key="groupedReport.id"
|
||||||
|
:timestamp="parseTimestamp(groupedReport.date)"
|
||||||
|
placement="top"
|
||||||
|
class="timeline-item-container">
|
||||||
|
<el-card class="grouped-report">
|
||||||
|
<div class="header-container">
|
||||||
|
<div>
|
||||||
|
<h3 class="report-title">{{ $t('reports.reportsOn') }} {{ groupedReport.account.display_name }}</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-dropdown trigger="click">
|
||||||
|
<el-button plain size="small" icon="el-icon-edit">{{ $t('reports.changeAllReports') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item @click.native="changeAllReports('resolved', groupedReport.reports)">{{ $t('reports.resolveAll') }}</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.native="changeAllReports('open', groupedReport.reports)">{{ $t('reports.reopenAll') }}</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.native="changeAllReports('closed', groupedReport.reports)">{{ $t('reports.closeAll') }}</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
<moderate-user-dropdown :account="groupedReport.account"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="line"/>
|
||||||
|
<span class="report-row-key">{{ $t('reports.account') }}:</span>
|
||||||
|
<img
|
||||||
|
:src="groupedReport.account.avatar"
|
||||||
|
alt="avatar"
|
||||||
|
class="avatar-img">
|
||||||
|
<a :href="groupedReport.account.url" target="_blank">
|
||||||
|
<span>{{ groupedReport.account.nickname }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="line"/>
|
||||||
|
<span class="report-row-key">{{ $t('reports.actors') }}:</span>
|
||||||
|
<span v-for="(actor, index) in groupedReport.actors" :key="actor.id">
|
||||||
|
<a :href="actor.url" target="_blank">
|
||||||
|
{{ actor.acct }}<span v-if="index < groupedReport.actors.length - 1">, </span>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="groupedReport.status">
|
||||||
|
<div class="line"/>
|
||||||
|
<span class="report-row-key">{{ $t('reports.reportedStatus') }}:</span>
|
||||||
|
<status :status="groupedReport.status" class="reported-status"/>
|
||||||
|
</div>
|
||||||
|
<div v-if="groupedReport.reports">
|
||||||
|
<el-collapse>
|
||||||
|
<el-collapse-item :title="$t('reports.reports')">
|
||||||
|
<report-card :reports="groupedReport.reports"/>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-timeline-item>
|
||||||
|
</el-timeline>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import moment from 'moment'
|
||||||
|
import ModerateUserDropdown from './ModerateUserDropdown'
|
||||||
|
import ReportCard from './ReportCard'
|
||||||
|
import Status from '../../status/Status'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Report',
|
||||||
|
components: { ModerateUserDropdown, ReportCard, Status },
|
||||||
|
props: {
|
||||||
|
groupedReports: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeAllReports(reportState, groupOfReports) {
|
||||||
|
const reportsData = groupOfReports.map(report => {
|
||||||
|
return { id: report.id, state: reportState }
|
||||||
|
})
|
||||||
|
this.$store.dispatch('ChangeReportState', reportsData)
|
||||||
|
},
|
||||||
|
parseTimestamp(timestamp) {
|
||||||
|
return moment(timestamp).format('L HH:mm')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel='stylesheet/scss' lang='scss'>
|
||||||
|
a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.avatar-img {
|
||||||
|
vertical-align: bottom;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.el-card__body {
|
||||||
|
padding: 17px;
|
||||||
|
}
|
||||||
|
.el-card__header {
|
||||||
|
background-color: #FAFAFA;
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
.el-icon-arrow-right {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
.header-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: baseline;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.line {
|
||||||
|
width: 100%;
|
||||||
|
height: 0;
|
||||||
|
border: 0.5px solid #EBEEF5;
|
||||||
|
margin: 15px 0 15px;
|
||||||
|
}
|
||||||
|
.report-title {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.report-row-key {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.reported-status {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
@media
|
||||||
|
only screen and (max-width: 760px),
|
||||||
|
(min-device-width: 768px) and (max-device-width: 1024px) {
|
||||||
|
.header-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
86
src/views/reports/components/ModerateUserDropdown.vue
Normal file
86
src/views/reports/components/ModerateUserDropdown.vue
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<template>
|
||||||
|
<el-dropdown trigger="click">
|
||||||
|
<el-button 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">
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="showDeactivatedButton(account)"
|
||||||
|
@click.native="handleDeactivation(account)">
|
||||||
|
{{ account.deactivated ? $t('users.activateAccount') : $t('users.deactivateAccount') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="showDeactivatedButton(account.id)"
|
||||||
|
@click.native="handleDeletion(account.id)">
|
||||||
|
{{ $t('users.deleteAccount') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
:divided="true"
|
||||||
|
:class="{ 'active-tag': account.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"/>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
:class="{ 'active-tag': account.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"/>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
:class="{ 'active-tag': account.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"/>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
:class="{ 'active-tag': account.tags.includes('sandbox') }"
|
||||||
|
@click.native="toggleTag(account, 'sandbox')">
|
||||||
|
{{ $t('users.sandbox') }}
|
||||||
|
<i v-if="account.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') }"
|
||||||
|
@click.native="toggleTag(account, 'disable_remote_subscription')">
|
||||||
|
{{ $t('users.disableRemoteSubscription') }}
|
||||||
|
<i v-if="account.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') }"
|
||||||
|
@click.native="toggleTag(account, 'disable_any_subscription')">
|
||||||
|
{{ $t('users.disableAnySubscription') }}
|
||||||
|
<i v-if="account.tags.includes('disable_any_subscription')" class="el-icon-check"/>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ModerateUserDropdown',
|
||||||
|
props: {
|
||||||
|
account: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleDeactivation({ nickname }) {
|
||||||
|
this.$store.dispatch('ToggleUserActivation', nickname)
|
||||||
|
},
|
||||||
|
handleDeletion(user) {
|
||||||
|
this.$store.dispatch('DeleteUser', user)
|
||||||
|
},
|
||||||
|
showDeactivatedButton(id) {
|
||||||
|
return this.$store.state.user.id !== id
|
||||||
|
},
|
||||||
|
toggleTag(user, tag) {
|
||||||
|
user.tags.includes(tag)
|
||||||
|
? this.$store.dispatch('RemoveTag', { users: [user], tag })
|
||||||
|
: this.$store.dispatch('AddTag', { users: [user], tag })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
250
src/views/reports/components/Report.vue
Normal file
250
src/views/reports/components/Report.vue
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-timeline class="timeline">
|
||||||
|
<el-timeline-item
|
||||||
|
v-for="report in reports"
|
||||||
|
:timestamp="parseTimestamp(report.created_at)"
|
||||||
|
:key="report.id"
|
||||||
|
placement="top"
|
||||||
|
class="timeline-item-container">
|
||||||
|
<el-card>
|
||||||
|
<div class="header-container">
|
||||||
|
<div>
|
||||||
|
<h3 class="report-title">{{ $t('reports.reportOn') }} {{ report.account.display_name }}</h3>
|
||||||
|
<h5 class="id">{{ $t('reports.id') }}: {{ report.id }}</h5>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-tag :type="getStateType(report.state)" size="large">{{ 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>
|
||||||
|
<moderate-user-dropdown :account="report.account"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="line"/>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<div v-if="report.content.length > 0">
|
||||||
|
<div class="line"/>
|
||||||
|
<span class="report-row-key">{{ $t('reports.content') }}:
|
||||||
|
<span>{{ report.content }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="line"/>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<div v-if="report.statuses.length > 0" class="statuses">
|
||||||
|
<el-collapse>
|
||||||
|
<el-collapse-item :title="getStatusesTitle(report.statuses)">
|
||||||
|
<div v-for="status in report.statuses" :key="status.id">
|
||||||
|
<status :status="status" :page="currentPage"/>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-timeline-item>
|
||||||
|
</el-timeline>
|
||||||
|
<div v-if="!loading" class="reports-pagination">
|
||||||
|
<el-pagination
|
||||||
|
:total="totalReportsCount"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-size="pageSize"
|
||||||
|
background
|
||||||
|
layout="prev, pager, next"
|
||||||
|
@current-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import moment from 'moment'
|
||||||
|
import Status from '../../status/Status'
|
||||||
|
import ModerateUserDropdown from './ModerateUserDropdown'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Report',
|
||||||
|
components: { Status, ModerateUserDropdown },
|
||||||
|
props: {
|
||||||
|
reports: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
loading() {
|
||||||
|
return this.$store.state.reports.loading
|
||||||
|
},
|
||||||
|
pageSize() {
|
||||||
|
return this.$store.state.reports.pageSize
|
||||||
|
},
|
||||||
|
totalReportsCount() {
|
||||||
|
return this.$store.state.reports.totalReportsCount
|
||||||
|
},
|
||||||
|
currentPage() {
|
||||||
|
return this.$store.state.reports.currentPage
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeReportState(state, id) {
|
||||||
|
this.$store.dispatch('ChangeReportState', [{ state, id }])
|
||||||
|
},
|
||||||
|
capitalizeFirstLetter(str) {
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||||
|
},
|
||||||
|
getStateType(state) {
|
||||||
|
switch (state) {
|
||||||
|
case 'closed':
|
||||||
|
return 'info'
|
||||||
|
case 'resolved':
|
||||||
|
return 'success'
|
||||||
|
default:
|
||||||
|
return 'primary'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getStatusesTitle(statuses) {
|
||||||
|
return `Reported statuses: ${statuses.length} item(s)`
|
||||||
|
},
|
||||||
|
handlePageChange(page) {
|
||||||
|
this.$store.dispatch('FetchReports', page)
|
||||||
|
},
|
||||||
|
parseTimestamp(timestamp) {
|
||||||
|
return moment(timestamp).format('L HH:mm')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel='stylesheet/scss' lang='scss'>
|
||||||
|
.account {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.avatar-img {
|
||||||
|
vertical-align: bottom;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.el-card__body {
|
||||||
|
padding: 17px;
|
||||||
|
}
|
||||||
|
.el-card__header {
|
||||||
|
background-color: #FAFAFA;
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
.el-collapse {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.el-collapse-item__header {
|
||||||
|
height: 46px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.el-collapse-item__content {
|
||||||
|
padding-bottom: 7px;
|
||||||
|
}
|
||||||
|
.el-icon-arrow-right {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
.el-icon-close {
|
||||||
|
padding: 10px 5px 10px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
height: 17px;
|
||||||
|
}
|
||||||
|
.header-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: baseline;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.id {
|
||||||
|
color: gray;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
.line {
|
||||||
|
width: 100%;
|
||||||
|
height: 0;
|
||||||
|
border: 0.5px solid #EBEEF5;
|
||||||
|
margin: 15px 0 15px;
|
||||||
|
}
|
||||||
|
.new-note {
|
||||||
|
p {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
height: 17px;
|
||||||
|
margin: 13px 0 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.note {
|
||||||
|
box-shadow: 0 2px 5px 0 rgba(0,0,0,.1);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.no-notes {
|
||||||
|
font-style: italic;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
.report-row-key {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.report-row-key {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.report-title {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.reports-pagination {
|
||||||
|
margin: 25px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.statuses {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
.submit-button {
|
||||||
|
display: block;
|
||||||
|
margin: 7px 0 17px auto;
|
||||||
|
}
|
||||||
|
.timestamp {
|
||||||
|
margin: 0;
|
||||||
|
font-style: italic;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
@media
|
||||||
|
only screen and (max-width: 760px),
|
||||||
|
(min-device-width: 768px) and (max-device-width: 1024px) {
|
||||||
|
.timeline-item-container {
|
||||||
|
.header-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
.id {
|
||||||
|
margin: 6px 0 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
130
src/views/reports/components/ReportCard.vue
Normal file
130
src/views/reports/components/ReportCard.vue
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
<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">{{ 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: 760px),
|
||||||
|
(min-device-width: 768px) and (max-device-width: 1024px) {
|
||||||
|
.el-card__header {
|
||||||
|
padding: 10px 17px;
|
||||||
|
}
|
||||||
|
.report-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
.report-actor-container {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.report-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -44,7 +44,7 @@ export default {
|
||||||
toggleFilters() {
|
toggleFilters() {
|
||||||
this.$store.dispatch('SetFilter', this.$data.filter)
|
this.$store.dispatch('SetFilter', this.$data.filter)
|
||||||
this.$store.dispatch('ClearFetchedReports')
|
this.$store.dispatch('ClearFetchedReports')
|
||||||
this.$store.dispatch('FetchReports')
|
this.$store.dispatch('FetchReports', 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-collapse-item :title="getStatusesTitle(report.statuses)">
|
|
||||||
<el-card v-for="status in report.statuses" :key="status.id" class="status-card">
|
|
||||||
<div slot="header">
|
|
||||||
<div class="status-header">
|
|
||||||
<div class="status-account-container">
|
|
||||||
<div class="status-account">
|
|
||||||
<img :src="status.account.avatar" class="status-avatar-img">
|
|
||||||
<h3 class="status-account-name">{{ status.account.display_name }}</h3>
|
|
||||||
</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>
|
|
||||||
<el-tag size="large">{{ capitalizeFirstLetter(status.visibility) }}</el-tag>
|
|
||||||
<el-dropdown trigger="click">
|
|
||||||
<el-button plain size="small" icon="el-icon-edit" class="status-actions-button">
|
|
||||||
{{ $t('reports.changeScope') }}<i class="el-icon-arrow-down el-icon--right"/>
|
|
||||||
</el-button>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="!status.sensitive"
|
|
||||||
@click.native="changeStatus(status.id, true, status.visibility, report.id)">
|
|
||||||
{{ $t('reports.addSensitive') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="status.sensitive"
|
|
||||||
@click.native="changeStatus(status.id, false, status.visibility, report.id)">
|
|
||||||
{{ $t('reports.removeSensitive') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="status.visibility !== 'public'"
|
|
||||||
@click.native="changeStatus(status.id, status.sensitive, 'public', report.id)">
|
|
||||||
{{ $t('reports.public') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="status.visibility !== 'private'"
|
|
||||||
@click.native="changeStatus(status.id, status.sensitive, 'private', report.id)">
|
|
||||||
{{ $t('reports.private') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="status.visibility !== 'unlisted'"
|
|
||||||
@click.native="changeStatus(status.id, status.sensitive, 'unlisted', report.id)">
|
|
||||||
{{ $t('reports.unlisted') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
@click.native="deleteStatus(status.id, report.id)">
|
|
||||||
{{ $t('reports.deleteStatus') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-body">
|
|
||||||
<span class="status-content" v-html="status.content"/>
|
|
||||||
<a :href="status.url" target="_blank" class="account">
|
|
||||||
{{ parseTimestamp(status.created_at) }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-collapse-item>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import moment from 'moment'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Statuses',
|
|
||||||
props: {
|
|
||||||
report: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
capitalizeFirstLetter(str) {
|
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
||||||
},
|
|
||||||
changeStatus(statusId, isSensitive, visibility, reportId) {
|
|
||||||
this.$store.dispatch('ChangeStatusScope', { statusId, isSensitive, visibility, reportId })
|
|
||||||
},
|
|
||||||
deleteStatus(statusId, reportId) {
|
|
||||||
this.$confirm('Are you sure you want to delete this status?', 'Warning', {
|
|
||||||
confirmButtonText: 'OK',
|
|
||||||
cancelButtonText: 'Cancel',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
this.$store.dispatch('DeleteStatus', { statusId, reportId })
|
|
||||||
this.$message({
|
|
||||||
type: 'success',
|
|
||||||
message: 'Delete completed'
|
|
||||||
})
|
|
||||||
}).catch(() => {
|
|
||||||
this.$message({
|
|
||||||
type: 'info',
|
|
||||||
message: 'Delete canceled'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getStatusesTitle(statuses) {
|
|
||||||
return `Reported statuses: ${statuses.length} item(s)`
|
|
||||||
},
|
|
||||||
parseTimestamp(timestamp) {
|
|
||||||
return moment(timestamp).format('YYYY-MM-DD HH:mm')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style rel='stylesheet/scss' lang='scss'>
|
|
||||||
.account {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
.status-account {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.status-avatar-img {
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
.status-account-name {
|
|
||||||
margin: 0;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
.status-body {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.status-content {
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
.status-card {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
.status-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
@media
|
|
||||||
only screen and (max-width: 760px),
|
|
||||||
(min-device-width: 768px) and (max-device-width: 1024px) {
|
|
||||||
.el-message {
|
|
||||||
min-width: 80%;
|
|
||||||
}
|
|
||||||
.el-message-box {
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
.status-card {
|
|
||||||
.el-card__header {
|
|
||||||
padding: 10px 17px
|
|
||||||
}
|
|
||||||
.el-tag {
|
|
||||||
margin: 3px 4px 3px 0;
|
|
||||||
}
|
|
||||||
.status-account-container {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
.status-actions-button {
|
|
||||||
margin: 3px 0 3px;
|
|
||||||
}
|
|
||||||
.status-actions {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
.status-header {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,271 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-timeline-item :timestamp="parseTimestamp(report.created_at)" placement="top" class="timeline-item-container">
|
|
||||||
<el-card>
|
|
||||||
<div class="header-container">
|
|
||||||
<div>
|
|
||||||
<h3 class="report-title">Report on {{ report.account.display_name }}</h3>
|
|
||||||
<h5 class="id">ID: {{ report.id }}</h5>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<el-tag :type="getStateType(report.state)" size="large">{{ 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>
|
|
||||||
<el-dropdown trigger="click">
|
|
||||||
<el-button 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">
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="showDeactivatedButton(report.account)"
|
|
||||||
@click.native="toggleActivation(report.account)">
|
|
||||||
{{ report.account.deactivated ? $t('users.activateAccount') : $t('users.deactivateAccount') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="showDeactivatedButton(report.account.id)"
|
|
||||||
@click.native="handleDeletion(report.account.id)">
|
|
||||||
{{ $t('users.deleteAccount') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
:divided="true"
|
|
||||||
:class="{ 'active-tag': report.account.tags.includes('force_nsfw') }"
|
|
||||||
@click.native="toggleTag(report.account, 'force_nsfw')">
|
|
||||||
{{ $t('users.forceNsfw') }}
|
|
||||||
<i v-if="report.account.tags.includes('force_nsfw')" class="el-icon-check"/>
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
:class="{ 'active-tag': report.account.tags.includes('strip_media') }"
|
|
||||||
@click.native="toggleTag(report.account, 'strip_media')">
|
|
||||||
{{ $t('users.stripMedia') }}
|
|
||||||
<i v-if="report.account.tags.includes('strip_media')" class="el-icon-check"/>
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
:class="{ 'active-tag': report.account.tags.includes('force_unlisted') }"
|
|
||||||
@click.native="toggleTag(report.account, 'force_unlisted')">
|
|
||||||
{{ $t('users.forceUnlisted') }}
|
|
||||||
<i v-if="report.account.tags.includes('force_unlisted')" class="el-icon-check"/>
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
:class="{ 'active-tag': report.account.tags.includes('sandbox') }"
|
|
||||||
@click.native="toggleTag(report.account, 'sandbox')">
|
|
||||||
{{ $t('users.sandbox') }}
|
|
||||||
<i v-if="report.account.tags.includes('sandbox')" class="el-icon-check"/>
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="report.account.local"
|
|
||||||
:class="{ 'active-tag': report.account.tags.includes('disable_remote_subscription') }"
|
|
||||||
@click.native="toggleTag(report.account, 'disable_remote_subscription')">
|
|
||||||
{{ $t('users.disableRemoteSubscription') }}
|
|
||||||
<i v-if="report.account.tags.includes('disable_remote_subscription')" class="el-icon-check"/>
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-if="report.account.local"
|
|
||||||
:class="{ 'active-tag': report.account.tags.includes('disable_any_subscription') }"
|
|
||||||
@click.native="toggleTag(report.account, 'disable_any_subscription')">
|
|
||||||
{{ $t('users.disableAnySubscription') }}
|
|
||||||
<i v-if="report.account.tags.includes('disable_any_subscription')" class="el-icon-check"/>
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="line"/>
|
|
||||||
<span class="report-row-key">Account:</span>
|
|
||||||
<img
|
|
||||||
:src="report.account.avatar"
|
|
||||||
alt="avatar"
|
|
||||||
class="avatar-img">
|
|
||||||
<a :href="report.account.url" target="_blank" class="account">
|
|
||||||
<span class="report-row-value">{{ report.account.acct }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div v-if="report.content.length > 0">
|
|
||||||
<div class="line"/>
|
|
||||||
<span class="report-row-key">Content:
|
|
||||||
<span class="report-row-value">{{ report.content }}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="line"/>
|
|
||||||
<span class="report-row-key">Actor:</span>
|
|
||||||
<img
|
|
||||||
:src="report.actor.avatar"
|
|
||||||
alt="avatar"
|
|
||||||
class="avatar-img">
|
|
||||||
<a :href="report.actor.url" target="_blank" class="account">
|
|
||||||
<span class="report-row-value">{{ report.actor.acct }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div v-if="report.statuses.length > 0" class="statuses">
|
|
||||||
<el-collapse>
|
|
||||||
<statuses :report="report"/>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-timeline-item>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import moment from 'moment'
|
|
||||||
import Statuses from './Statuses'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'TimelineItem',
|
|
||||||
components: { Statuses },
|
|
||||||
props: {
|
|
||||||
report: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeReportState(reportState, reportId) {
|
|
||||||
this.$store.dispatch('ChangeReportState', { reportState, reportId })
|
|
||||||
},
|
|
||||||
capitalizeFirstLetter(str) {
|
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
||||||
},
|
|
||||||
getStateType(state) {
|
|
||||||
switch (state) {
|
|
||||||
case 'closed':
|
|
||||||
return 'info'
|
|
||||||
case 'resolved':
|
|
||||||
return 'success'
|
|
||||||
default:
|
|
||||||
return 'primary'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleDeletion(user) {
|
|
||||||
this.$store.dispatch('DeleteUsers', [user])
|
|
||||||
},
|
|
||||||
parseTimestamp(timestamp) {
|
|
||||||
return moment(timestamp).format('L HH:mm')
|
|
||||||
},
|
|
||||||
showDeactivatedButton(id) {
|
|
||||||
return this.$store.state.user.id !== id
|
|
||||||
},
|
|
||||||
toggleActivation(user) {
|
|
||||||
user.deactivated
|
|
||||||
? this.$store.dispatch('ActivateUsers', [user])
|
|
||||||
: this.$store.dispatch('DeactivateUsers', [user])
|
|
||||||
},
|
|
||||||
toggleTag(user, tag) {
|
|
||||||
user.tags.includes(tag)
|
|
||||||
? this.$store.dispatch('RemoveTag', { users: [user], tag })
|
|
||||||
: this.$store.dispatch('AddTag', { users: [user], tag })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style rel='stylesheet/scss' lang='scss'>
|
|
||||||
.account {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
.avatar-img {
|
|
||||||
vertical-align: bottom;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
.el-card__body {
|
|
||||||
padding: 17px;
|
|
||||||
}
|
|
||||||
.el-card__header {
|
|
||||||
background-color: #FAFAFA;
|
|
||||||
padding: 10px 20px;
|
|
||||||
}
|
|
||||||
.el-collapse {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.el-collapse-item__header {
|
|
||||||
height: 46px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.el-collapse-item__content {
|
|
||||||
padding-bottom: 7px;
|
|
||||||
}
|
|
||||||
.el-icon-arrow-right {
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
.el-icon-close {
|
|
||||||
padding: 10px 5px 10px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
h4 {
|
|
||||||
margin: 0;
|
|
||||||
height: 17px;
|
|
||||||
}
|
|
||||||
.header-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: baseline;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
.id {
|
|
||||||
color: gray;
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
.line {
|
|
||||||
width: 100%;
|
|
||||||
height: 0;
|
|
||||||
border: 0.5px solid #EBEEF5;
|
|
||||||
margin: 15px 0 15px;
|
|
||||||
}
|
|
||||||
.new-note {
|
|
||||||
p {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
height: 17px;
|
|
||||||
margin: 13px 0 7px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.note {
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(0,0,0,.1);
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.no-notes {
|
|
||||||
font-style: italic;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
.report-row-key {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
.report-row-key {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.report-title {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.statuses {
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
.submit-button {
|
|
||||||
display: block;
|
|
||||||
margin: 7px 0 17px auto;
|
|
||||||
}
|
|
||||||
.timestamp {
|
|
||||||
margin: 0;
|
|
||||||
font-style: italic;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
@media
|
|
||||||
only screen and (max-width: 760px),
|
|
||||||
(min-device-width: 768px) and (max-device-width: 1024px) {
|
|
||||||
.timeline-item-container {
|
|
||||||
.header-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 80px;
|
|
||||||
}
|
|
||||||
.id {
|
|
||||||
margin: 6px 0 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,13 +1,22 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="reports-container">
|
<div class="reports-container">
|
||||||
<h1>{{ $t('reports.reports') }}</h1>
|
<h1 v-if="groupReports">
|
||||||
|
{{ $t('reports.groupedReports') }}
|
||||||
|
<span class="report-count">({{ normalizedReportsCount }})</span>
|
||||||
|
</h1>
|
||||||
|
<h1 v-else>
|
||||||
|
{{ $t('reports.reports') }}
|
||||||
|
<span class="report-count">({{ normalizedReportsCount }})</span>
|
||||||
|
</h1>
|
||||||
<div class="filter-container">
|
<div class="filter-container">
|
||||||
<reports-filter/>
|
<reports-filter v-if="!groupReports"/>
|
||||||
|
<el-checkbox v-model="groupReports" class="group-reports-checkbox">
|
||||||
|
Group reports by statuses
|
||||||
|
</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<el-timeline class="timeline">
|
<grouped-report v-loading="loading" v-if="groupReports" :grouped-reports="groupedReports"/>
|
||||||
<timeline-item v-loading="loading" v-for="report in reports" :report="report" :key="report.id"/>
|
<report v-loading="loading" v-else :reports="reports"/>
|
||||||
</el-timeline>
|
|
||||||
<div v-if="reports.length === 0" class="no-reports-message">
|
<div v-if="reports.length === 0" class="no-reports-message">
|
||||||
<p>There are no reports to display</p>
|
<p>There are no reports to display</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,34 +25,44 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TimelineItem from './components/TimelineItem'
|
import GroupedReport from './components/GroupedReport'
|
||||||
|
import numeral from 'numeral'
|
||||||
|
import Report from './components/Report'
|
||||||
import ReportsFilter from './components/ReportsFilter'
|
import ReportsFilter from './components/ReportsFilter'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { TimelineItem, ReportsFilter },
|
components: { GroupedReport, Report, ReportsFilter },
|
||||||
computed: {
|
computed: {
|
||||||
|
groupedReports() {
|
||||||
|
return this.$store.state.reports.fetchedGroupedReports
|
||||||
|
},
|
||||||
|
groupReports: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.reports.groupReports
|
||||||
|
},
|
||||||
|
set() {
|
||||||
|
this.toggleReportsGrouping()
|
||||||
|
}
|
||||||
|
},
|
||||||
loading() {
|
loading() {
|
||||||
return this.$store.state.users.loading
|
return this.$store.state.reports.loading
|
||||||
|
},
|
||||||
|
normalizedReportsCount() {
|
||||||
|
return this.groupReports
|
||||||
|
? numeral(this.$store.state.reports.fetchedGroupedReports.length).format('0a')
|
||||||
|
: numeral(this.$store.state.reports.totalReportsCount).format('0a')
|
||||||
},
|
},
|
||||||
reports() {
|
reports() {
|
||||||
return this.$store.state.reports.fetchedReports
|
return this.$store.state.reports.fetchedReports
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$store.dispatch('FetchReports')
|
this.$store.dispatch('FetchReports', 1)
|
||||||
},
|
this.$store.dispatch('FetchGroupedReports')
|
||||||
created() {
|
|
||||||
window.addEventListener('scroll', this.handleScroll)
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
window.removeEventListener('scroll', this.handleScroll)
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleScroll(reports) {
|
toggleReportsGrouping() {
|
||||||
const bottomOfWindow = document.documentElement.scrollHeight - document.documentElement.scrollTop === document.documentElement.clientHeight
|
this.$store.dispatch('ToggleReportsGrouping')
|
||||||
if (bottomOfWindow) {
|
|
||||||
this.$store.dispatch('FetchReports')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,16 +75,24 @@ export default {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
.filter-container {
|
.filter-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
margin: 22px 15px 22px 15px;
|
margin: 22px 15px 22px 15px;
|
||||||
padding-bottom: 0
|
padding-bottom: 0
|
||||||
}
|
}
|
||||||
|
.group-reports-checkbox {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
h1 {
|
h1 {
|
||||||
margin: 22px 0 0 15px;
|
margin: 22px 0 0 15px;
|
||||||
}
|
}
|
||||||
.no-reports-message {
|
.no-reports-message {
|
||||||
color: gray;
|
color: gray;
|
||||||
margin-left: 19px
|
margin-left: 19px
|
||||||
|
}
|
||||||
|
.report-count {
|
||||||
|
color: gray;
|
||||||
|
font-size: 28px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media
|
@media
|
||||||
|
@ -78,9 +105,9 @@ only screen and (max-width: 760px),
|
||||||
.filter-container {
|
.filter-container {
|
||||||
margin: 0 10px
|
margin: 0 10px
|
||||||
}
|
}
|
||||||
.timeline {
|
|
||||||
margin: 20px 20px 20px 18px
|
|
||||||
}
|
}
|
||||||
|
#app > div > div.main-container > section > div > div.block > ul {
|
||||||
|
margin: 45px 45px 5px 19px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
269
src/views/status/Status.vue
Normal file
269
src/views/status/Status.vue
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-card v-if="!status.deleted" class="status-card">
|
||||||
|
<div slot="header">
|
||||||
|
<div class="status-header">
|
||||||
|
<div class="status-account-container">
|
||||||
|
<div class="status-account">
|
||||||
|
<img :src="status.account.avatar" class="status-avatar-img">
|
||||||
|
<h3 class="status-account-name">{{ status.account.display_name }}</h3>
|
||||||
|
</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>
|
||||||
|
<el-tag size="large">{{ capitalizeFirstLetter(status.visibility) }}</el-tag>
|
||||||
|
<el-dropdown trigger="click">
|
||||||
|
<el-button plain size="small" icon="el-icon-edit" class="status-actions-button">
|
||||||
|
{{ $t('reports.changeScope') }}<i class="el-icon-arrow-down el-icon--right"/>
|
||||||
|
</el-button>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="!status.sensitive"
|
||||||
|
@click.native="changeStatus(status.id, true, status.visibility)">
|
||||||
|
{{ $t('reports.addSensitive') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="status.sensitive"
|
||||||
|
@click.native="changeStatus(status.id, false, status.visibility)">
|
||||||
|
{{ $t('reports.removeSensitive') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="status.visibility !== 'public'"
|
||||||
|
@click.native="changeStatus(status.id, status.sensitive, 'public')">
|
||||||
|
{{ $t('reports.public') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="status.visibility !== 'private'"
|
||||||
|
@click.native="changeStatus(status.id, status.sensitive, 'private')">
|
||||||
|
{{ $t('reports.private') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="status.visibility !== 'unlisted'"
|
||||||
|
@click.native="changeStatus(status.id, status.sensitive, 'unlisted')">
|
||||||
|
{{ $t('reports.unlisted') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
@click.native="deleteStatus(status.id)">
|
||||||
|
{{ $t('reports.deleteStatus') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-body">
|
||||||
|
<div v-if="status.spoiler_text">
|
||||||
|
<strong>{{ status.spoiler_text }}</strong>
|
||||||
|
<el-button v-if="!showHiddenStatus" size="mini" class="show-more-button" @click="showHiddenStatus = true">Show more</el-button>
|
||||||
|
<el-button v-if="showHiddenStatus" size="mini" class="show-more-button" @click="showHiddenStatus = false">Show less</el-button>
|
||||||
|
<div v-if="showHiddenStatus">
|
||||||
|
<span class="status-content" v-html="status.content"/>
|
||||||
|
<div v-if="status.poll" class="poll">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(option, index) in status.poll.options" :key="index">
|
||||||
|
{{ option.title }}
|
||||||
|
<el-progress :percentage="optionPercent(status.poll, option)" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div v-for="(attachment, index) in status.media_attachments" :key="index" class="image">
|
||||||
|
<img :src="attachment.preview_url">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="!status.spoiler_text">
|
||||||
|
<span class="status-content" v-html="status.content"/>
|
||||||
|
<div v-if="status.poll" class="poll">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(option, index) in status.poll.options" :key="index">
|
||||||
|
{{ option.title }}
|
||||||
|
<el-progress :percentage="optionPercent(status.poll, option)" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div v-for="(attachment, index) in status.media_attachments" :key="index" class="image">
|
||||||
|
<img :src="attachment.preview_url">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a :href="status.url" target="_blank" class="account">
|
||||||
|
{{ parseTimestamp(status.created_at) }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-else class="status-card">
|
||||||
|
<div slot="header">
|
||||||
|
<div class="status-header">
|
||||||
|
<div class="status-account-container">
|
||||||
|
<div class="status-account">
|
||||||
|
<h4 class="status-deleted">{{ $t('reports.statusDeleted') }}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-body">
|
||||||
|
<span v-if="status.content" class="status-content" v-html="status.content"/>
|
||||||
|
<span v-else class="status-without-content">no content</span>
|
||||||
|
</div>
|
||||||
|
<a v-if="status.created_at" :href="status.url" target="_blank" class="account">
|
||||||
|
{{ parseTimestamp(status.created_at) }}
|
||||||
|
</a>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Status',
|
||||||
|
props: {
|
||||||
|
status: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
godmode: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showHiddenStatus: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
capitalizeFirstLetter(str) {
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||||
|
},
|
||||||
|
changeStatus(statusId, isSensitive, visibility) {
|
||||||
|
this.$store.dispatch('ChangeStatusScope', { statusId, isSensitive, visibility, reportCurrentPage: this.page, userId: this.userId, godmode: this.godmode })
|
||||||
|
},
|
||||||
|
deleteStatus(statusId) {
|
||||||
|
this.$confirm('Are you sure you want to delete this status?', 'Warning', {
|
||||||
|
confirmButtonText: 'OK',
|
||||||
|
cancelButtonText: 'Cancel',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
this.$store.dispatch('DeleteStatus', { statusId, reportCurrentPage: this.page, userId: this.userId, godmode: this.godmode })
|
||||||
|
this.$message({
|
||||||
|
type: 'success',
|
||||||
|
message: 'Delete completed'
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message({
|
||||||
|
type: 'info',
|
||||||
|
message: 'Delete canceled'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
optionPercent(poll, pollOption) {
|
||||||
|
const allVotes = poll.options.reduce((acc, option) => (acc + option.votes_count), 0)
|
||||||
|
if (allVotes === 0) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return +(pollOption.votes_count / allVotes * 100).toFixed(1)
|
||||||
|
},
|
||||||
|
parseTimestamp(timestamp) {
|
||||||
|
return moment(timestamp).format('YYYY-MM-DD HH:mm')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel='stylesheet/scss' lang='scss'>
|
||||||
|
.account {
|
||||||
|
text-decoration: underline;
|
||||||
|
line-height: 26px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.image {
|
||||||
|
width: 20%;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.show-more-button {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.status-account {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.status-avatar-img {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.status-account-name {
|
||||||
|
margin: 0;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
.status-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.status-content {
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
.status-card {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.status-deleted {
|
||||||
|
font-style: italic;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
.status-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.status-without-content {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
@media
|
||||||
|
only screen and (max-width: 760px),
|
||||||
|
(min-device-width: 768px) and (max-device-width: 1024px) {
|
||||||
|
.el-message {
|
||||||
|
min-width: 80%;
|
||||||
|
}
|
||||||
|
.el-message-box {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
.status-card {
|
||||||
|
.el-card__header {
|
||||||
|
padding: 10px 17px;
|
||||||
|
}
|
||||||
|
.el-tag {
|
||||||
|
margin: 3px 4px 3px 0;
|
||||||
|
}
|
||||||
|
.status-account-container {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.status-actions-button {
|
||||||
|
margin: 3px 0 3px;
|
||||||
|
}
|
||||||
|
.status-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.status-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<main v-if="!loading">
|
<main v-if="!userProfileLoading">
|
||||||
<header>
|
<header>
|
||||||
<el-avatar :src="user.avatar" size="large" />
|
<el-avatar :src="user.avatar" size="large" />
|
||||||
<h1>{{ user.display_name }}</h1>
|
<h1>{{ user.display_name }}</h1>
|
||||||
|
@ -71,23 +71,9 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-col :span="18">
|
<el-col :span="18">
|
||||||
<el-timeline class="statuses">
|
<el-timeline v-if="!statusesLoading" class="statuses">
|
||||||
<el-timeline-item v-for="status in statuses" :timestamp="createdAtLocaleString(status.created_at)" :key="status.id">
|
<el-timeline-item v-for="status in statuses" :key="status.id">
|
||||||
<el-card>
|
<status :status="status" :user-id="user.id" :godmode="showPrivate"/>
|
||||||
<strong v-if="status.spoiler_text">{{ status.spoiler_text }}</strong>
|
|
||||||
<p v-if="status.content" v-html="status.content" />
|
|
||||||
<div v-if="status.poll" class="poll">
|
|
||||||
<ul>
|
|
||||||
<li v-for="(option, index) in status.poll.options" :key="index">
|
|
||||||
{{ option.title }}
|
|
||||||
<el-progress :percentage="optionPercent(status.poll, option)" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div v-for="(attachment, index) in status.media_attachments" :key="index" class="image">
|
|
||||||
<img :src="attachment.preview_url">
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-timeline-item>
|
</el-timeline-item>
|
||||||
</el-timeline>
|
</el-timeline>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -96,45 +82,36 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Status from '../status/Status'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'UsersShow',
|
name: 'UsersShow',
|
||||||
|
components: { Status },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showPrivate: false
|
showPrivate: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
loading() {
|
statuses() {
|
||||||
return this.$store.state.userProfile.loading
|
return this.$store.state.userProfile.statuses
|
||||||
|
},
|
||||||
|
statusesLoading() {
|
||||||
|
return this.$store.state.userProfile.statusesLoading
|
||||||
},
|
},
|
||||||
user() {
|
user() {
|
||||||
return this.$store.state.userProfile.user
|
return this.$store.state.userProfile.user
|
||||||
},
|
},
|
||||||
statuses() {
|
userProfileLoading() {
|
||||||
return this.$store.state.userProfile.statuses
|
return this.$store.state.userProfile.userProfileLoading
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
this.$store.dispatch('FetchData', { id: this.$route.params.id, godmode: false })
|
this.$store.dispatch('FetchUserProfile', { userId: this.$route.params.id, godmode: false })
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
optionPercent(poll, pollOption) {
|
|
||||||
const allVotes = poll.options.reduce((acc, option) => (acc + option.votes_count), 0)
|
|
||||||
if (allVotes === 0) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return +(pollOption.votes_count / allVotes * 100).toFixed(1)
|
|
||||||
},
|
|
||||||
createdAtLocaleString(createdAt) {
|
|
||||||
const date = new Date(createdAt)
|
|
||||||
|
|
||||||
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`
|
|
||||||
},
|
|
||||||
onTogglePrivate() {
|
onTogglePrivate() {
|
||||||
console.log(this.showPrivate)
|
this.$store.dispatch('FetchUserProfile', { userId: this.$route.params.id, godmode: this.showPrivate })
|
||||||
|
|
||||||
this.$store.dispatch('FetchData', { id: this.$route.params.id, godmode: this.showPrivate })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
47
test/views/reports/groupedReport.test.js
Normal file
47
test/views/reports/groupedReport.test.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import { mount, createLocalVue, config } from '@vue/test-utils'
|
||||||
|
import Element from 'element-ui'
|
||||||
|
import GroupedReport from '@/views/reports/components/GroupedReport'
|
||||||
|
import storeConfig from './store.conf'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
import flushPromises from 'flush-promises'
|
||||||
|
|
||||||
|
config.mocks["$t"] = () => {}
|
||||||
|
|
||||||
|
const localVue = createLocalVue()
|
||||||
|
localVue.use(Vuex)
|
||||||
|
localVue.use(Element)
|
||||||
|
|
||||||
|
jest.mock('@/api/reports')
|
||||||
|
|
||||||
|
describe('Grouped report', () => {
|
||||||
|
let store
|
||||||
|
|
||||||
|
beforeEach(async() => {
|
||||||
|
store = new Vuex.Store(cloneDeep(storeConfig))
|
||||||
|
store.dispatch('FetchGroupedReports')
|
||||||
|
await flushPromises()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes state of all reports in a group', async (done) => {
|
||||||
|
const groupedReports = store.state.reports.fetchedGroupedReports
|
||||||
|
const wrapper = mount(GroupedReport, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
groupedReports
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(groupedReports[0].reports[0].state).toBe('open')
|
||||||
|
expect(groupedReports[0].reports[1].state).toBe('resolved')
|
||||||
|
|
||||||
|
const button = wrapper.find(`.grouped-report .el-dropdown-menu__item:nth-child(3)`)
|
||||||
|
button.trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(store.state.reports.fetchedGroupedReports[0].reports[0].state).toBe('closed')
|
||||||
|
expect(store.state.reports.fetchedGroupedReports[0].reports[1].state).toBe('closed')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
|
@ -31,22 +31,7 @@ describe('Reports', () => {
|
||||||
|
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
const initialReports = store.state.reports.fetchedReports.length
|
const initialReports = store.state.reports.fetchedReports.length
|
||||||
expect(initialReports).toEqual(5)
|
expect(initialReports).toEqual(7)
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('loads more reports on scroll', async (done) => {
|
|
||||||
const wrapper = mount(Reports, {
|
|
||||||
store,
|
|
||||||
localVue
|
|
||||||
})
|
|
||||||
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports.length).toEqual(5)
|
|
||||||
|
|
||||||
window.dispatchEvent(new CustomEvent('scroll', { detail: 2000 }))
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports.length).toEqual(7)
|
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
75
test/views/reports/report.test.js
Normal file
75
test/views/reports/report.test.js
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import { mount, createLocalVue, config } from '@vue/test-utils'
|
||||||
|
import Element from 'element-ui'
|
||||||
|
import Report from '@/views/reports/components/Report'
|
||||||
|
import storeConfig from './store.conf'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
import flushPromises from 'flush-promises'
|
||||||
|
|
||||||
|
config.mocks["$t"] = () => {}
|
||||||
|
|
||||||
|
const localVue = createLocalVue()
|
||||||
|
localVue.use(Vuex)
|
||||||
|
localVue.use(Element)
|
||||||
|
|
||||||
|
jest.mock('@/api/reports')
|
||||||
|
|
||||||
|
describe('Report in a timeline', () => {
|
||||||
|
let store
|
||||||
|
|
||||||
|
beforeEach(async() => {
|
||||||
|
store = new Vuex.Store(cloneDeep(storeConfig))
|
||||||
|
store.dispatch('FetchReports')
|
||||||
|
await flushPromises()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes report state from open to resolved', async (done) => {
|
||||||
|
const reports = store.state.reports.fetchedReports
|
||||||
|
const wrapper = mount(Report, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
reports
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(reports[0].state).toBe('open')
|
||||||
|
|
||||||
|
const button = wrapper.find(`li.el-timeline-item:nth-child(1) li.el-dropdown-menu__item:nth-child(1)`)
|
||||||
|
button.trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
expect(store.state.reports.fetchedReports[0].state).toBe('resolved')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes report state from open to closed', async (done) => {
|
||||||
|
const reports = store.state.reports.fetchedReports
|
||||||
|
const wrapper = mount(Report, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
reports
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(reports[3].state).toBe('open')
|
||||||
|
|
||||||
|
const button = wrapper.find(`li.el-timeline-item:nth-child(4) li.el-dropdown-menu__item:nth-child(2)`)
|
||||||
|
button.trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
expect(store.state.reports.fetchedReports[3].state).toBe('closed')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows statuses', () => {
|
||||||
|
const reports = store.state.reports.fetchedReports
|
||||||
|
const wrapper = mount(Report, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
reports
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const statuses = wrapper.findAll(`.status-card`)
|
||||||
|
expect(statuses.length).toEqual(2)
|
||||||
|
})
|
||||||
|
})
|
|
@ -24,11 +24,11 @@ describe('Reports filter', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows open reports when "Open" filter is applied', async (done) => {
|
it('shows open reports when "Open" filter is applied', async (done) => {
|
||||||
expect(store.state.reports.fetchedReports.length).toEqual(5)
|
expect(store.state.reports.fetchedReports.length).toEqual(7)
|
||||||
|
|
||||||
store.dispatch('SetFilter', 'open')
|
store.dispatch('SetFilter', 'open')
|
||||||
store.dispatch('ClearFetchedReports')
|
store.dispatch('ClearFetchedReports')
|
||||||
store.dispatch('FetchReports')
|
store.dispatch('FetchReports', 1)
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(store.state.reports.fetchedReports.length).toEqual(2)
|
expect(store.state.reports.fetchedReports.length).toEqual(2)
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ describe('Reports filter', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows resolved reports when "Resolved" filter is applied', async (done) => {
|
it('shows resolved reports when "Resolved" filter is applied', async (done) => {
|
||||||
expect(store.state.reports.fetchedReports.length).toEqual(5)
|
expect(store.state.reports.fetchedReports.length).toEqual(7)
|
||||||
|
|
||||||
store.dispatch('SetFilter', 'resolved')
|
store.dispatch('SetFilter', 'resolved')
|
||||||
store.dispatch('ClearFetchedReports')
|
store.dispatch('ClearFetchedReports')
|
||||||
|
@ -48,7 +48,7 @@ describe('Reports filter', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows closed reports when "Closed" filter is applied', async (done) => {
|
it('shows closed reports when "Closed" filter is applied', async (done) => {
|
||||||
expect(store.state.reports.fetchedReports.length).toEqual(5)
|
expect(store.state.reports.fetchedReports.length).toEqual(7)
|
||||||
|
|
||||||
store.dispatch('SetFilter', 'closed')
|
store.dispatch('SetFilter', 'closed')
|
||||||
store.dispatch('ClearFetchedReports')
|
store.dispatch('ClearFetchedReports')
|
||||||
|
@ -60,7 +60,7 @@ describe('Reports filter', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows all users after removing filters', async (done) => {
|
it('shows all users after removing filters', async (done) => {
|
||||||
expect(store.state.reports.fetchedReports.length).toEqual(5)
|
expect(store.state.reports.fetchedReports.length).toEqual(7)
|
||||||
|
|
||||||
store.dispatch('SetFilter', 'open')
|
store.dispatch('SetFilter', 'open')
|
||||||
store.dispatch('ClearFetchedReports')
|
store.dispatch('ClearFetchedReports')
|
||||||
|
@ -72,7 +72,7 @@ describe('Reports filter', () => {
|
||||||
store.dispatch('ClearFetchedReports')
|
store.dispatch('ClearFetchedReports')
|
||||||
store.dispatch('FetchReports')
|
store.dispatch('FetchReports')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(store.state.reports.fetchedReports.length).toEqual(5)
|
expect(store.state.reports.fetchedReports.length).toEqual(7)
|
||||||
|
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|
151
test/views/reports/status.test.js
Normal file
151
test/views/reports/status.test.js
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import { mount, createLocalVue, config } from '@vue/test-utils'
|
||||||
|
import Element from 'element-ui'
|
||||||
|
import Status from '@/views/status/Status'
|
||||||
|
import storeConfig from './store.conf'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
import flushPromises from 'flush-promises'
|
||||||
|
|
||||||
|
config.mocks["$t"] = () => {}
|
||||||
|
|
||||||
|
const localVue = createLocalVue()
|
||||||
|
localVue.use(Vuex)
|
||||||
|
localVue.use(Element)
|
||||||
|
|
||||||
|
jest.mock('@/api/reports')
|
||||||
|
jest.mock('@/api/status')
|
||||||
|
|
||||||
|
describe('Status in reports', () => {
|
||||||
|
let store
|
||||||
|
|
||||||
|
beforeEach(async() => {
|
||||||
|
store = new Vuex.Store(cloneDeep(storeConfig))
|
||||||
|
store.dispatch('FetchReports', 1)
|
||||||
|
await flushPromises()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds sensitive flag to a status', async (done) => {
|
||||||
|
const status = store.state.reports.fetchedReports[4].statuses[0]
|
||||||
|
const wrapper = mount(Status, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
status,
|
||||||
|
page: 1,
|
||||||
|
userId: '7',
|
||||||
|
godmode: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const changeStatusStub = jest.fn()
|
||||||
|
wrapper.setMethods({ changeStatus: changeStatusStub })
|
||||||
|
|
||||||
|
const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(1)`)
|
||||||
|
button.trigger('click')
|
||||||
|
|
||||||
|
expect(wrapper.vm.changeStatus).toHaveBeenCalled()
|
||||||
|
expect(wrapper.vm.changeStatus).toHaveBeenCalledWith('11', true, 'public')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('removes sensitive flag to a status', async (done) => {
|
||||||
|
const status = store.state.reports.fetchedReports[4].statuses[1]
|
||||||
|
const wrapper = mount(Status, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
status,
|
||||||
|
page: 1,
|
||||||
|
userId: '7',
|
||||||
|
godmode: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const changeStatusStub = jest.fn()
|
||||||
|
wrapper.setMethods({ changeStatus: changeStatusStub })
|
||||||
|
|
||||||
|
const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(1)`)
|
||||||
|
button.trigger('click')
|
||||||
|
|
||||||
|
expect(wrapper.vm.changeStatus).toHaveBeenCalled()
|
||||||
|
expect(wrapper.vm.changeStatus).toHaveBeenCalledWith('10', false, 'unlisted')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes status visibility from public to unlisted', async (done) => {
|
||||||
|
const status = store.state.reports.fetchedReports[4].statuses[0]
|
||||||
|
const wrapper = mount(Status, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
status,
|
||||||
|
page: 1,
|
||||||
|
userId: '7',
|
||||||
|
godmode: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const changeStatusStub = jest.fn()
|
||||||
|
wrapper.setMethods({ changeStatus: changeStatusStub })
|
||||||
|
|
||||||
|
const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(3)`)
|
||||||
|
button.trigger('click')
|
||||||
|
|
||||||
|
expect(wrapper.vm.changeStatus).toHaveBeenCalled()
|
||||||
|
expect(wrapper.vm.changeStatus).toHaveBeenCalledWith('11', false, 'unlisted')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes status visibility from unlisted to private', async (done) => {
|
||||||
|
const status = store.state.reports.fetchedReports[4].statuses[1]
|
||||||
|
const wrapper = mount(Status, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
status,
|
||||||
|
page: 1,
|
||||||
|
userId: '7',
|
||||||
|
godmode: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const changeStatusStub = jest.fn()
|
||||||
|
wrapper.setMethods({ changeStatus: changeStatusStub })
|
||||||
|
|
||||||
|
const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(3)`)
|
||||||
|
button.trigger('click')
|
||||||
|
|
||||||
|
expect(wrapper.vm.changeStatus).toHaveBeenCalled()
|
||||||
|
expect(wrapper.vm.changeStatus).toHaveBeenCalledWith('10', true, 'private')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('deletes a status', async (done) => {
|
||||||
|
const status = store.state.reports.fetchedReports[4].statuses[1]
|
||||||
|
const wrapper = mount(Status, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
status,
|
||||||
|
page: 1,
|
||||||
|
userId: '7',
|
||||||
|
godmode: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const deleteStatusStub = jest.fn()
|
||||||
|
wrapper.setMethods({ deleteStatus: deleteStatusStub })
|
||||||
|
|
||||||
|
const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(4)`)
|
||||||
|
button.trigger('click')
|
||||||
|
|
||||||
|
expect(wrapper.vm.deleteStatus).toHaveBeenCalled()
|
||||||
|
expect(wrapper.vm.deleteStatus).toHaveBeenCalledWith('10')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
|
@ -2,6 +2,7 @@ import app from '@/store/modules/app'
|
||||||
import user from '@/store/modules/user'
|
import user from '@/store/modules/user'
|
||||||
import users from '@/store/modules/users'
|
import users from '@/store/modules/users'
|
||||||
import reports from '@/store/modules/reports'
|
import reports from '@/store/modules/reports'
|
||||||
|
import status from '@/store/modules/status'
|
||||||
import getters from '@/store/getters'
|
import getters from '@/store/getters'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -9,7 +10,8 @@ export default {
|
||||||
app,
|
app,
|
||||||
user,
|
user,
|
||||||
users,
|
users,
|
||||||
reports
|
reports,
|
||||||
|
status
|
||||||
},
|
},
|
||||||
getters
|
getters
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
import Vuex from 'vuex'
|
|
||||||
import { mount, createLocalVue, config } from '@vue/test-utils'
|
|
||||||
import Element from 'element-ui'
|
|
||||||
import TimelineItem from '@/views/reports/components/TimelineItem'
|
|
||||||
import storeConfig from './store.conf'
|
|
||||||
import { cloneDeep } from 'lodash'
|
|
||||||
import flushPromises from 'flush-promises'
|
|
||||||
|
|
||||||
config.mocks["$t"] = () => {}
|
|
||||||
|
|
||||||
const localVue = createLocalVue()
|
|
||||||
localVue.use(Vuex)
|
|
||||||
localVue.use(Element)
|
|
||||||
|
|
||||||
jest.mock('@/api/reports')
|
|
||||||
|
|
||||||
describe('Report in a timeline', () => {
|
|
||||||
let store
|
|
||||||
|
|
||||||
beforeEach(async() => {
|
|
||||||
store = new Vuex.Store(cloneDeep(storeConfig))
|
|
||||||
store.dispatch('FetchReports')
|
|
||||||
await flushPromises()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('changes report state from open to resolved', async (done) => {
|
|
||||||
const report = store.state.reports.fetchedReports[0]
|
|
||||||
const wrapper = mount(TimelineItem, {
|
|
||||||
store,
|
|
||||||
localVue,
|
|
||||||
propsData: {
|
|
||||||
report: report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(report.state).toBe('open')
|
|
||||||
|
|
||||||
const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(${1})`)
|
|
||||||
button.trigger('click')
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports[0].state).toBe('resolved')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('changes report state from open to closed', async (done) => {
|
|
||||||
const report = store.state.reports.fetchedReports[3]
|
|
||||||
const wrapper = mount(TimelineItem, {
|
|
||||||
store,
|
|
||||||
localVue,
|
|
||||||
propsData: {
|
|
||||||
report: report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(report.state).toBe('open')
|
|
||||||
|
|
||||||
const button = wrapper.find(`li.el-dropdown-menu__item:nth-child(${2})`)
|
|
||||||
button.trigger('click')
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports[3].state).toBe('closed')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('shows statuses', () => {
|
|
||||||
const report = store.state.reports.fetchedReports[4]
|
|
||||||
const wrapper = mount(TimelineItem, {
|
|
||||||
store,
|
|
||||||
localVue,
|
|
||||||
propsData: {
|
|
||||||
report: report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const statuses = wrapper.findAll(`.status-card`)
|
|
||||||
expect(statuses.length).toEqual(2)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adds sensitive flag to a status', async (done) => {
|
|
||||||
const report = store.state.reports.fetchedReports[4]
|
|
||||||
const wrapper = mount(TimelineItem, {
|
|
||||||
store,
|
|
||||||
localVue,
|
|
||||||
propsData: {
|
|
||||||
report: report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(report.statuses[0].sensitive).toBe(false)
|
|
||||||
|
|
||||||
const button = wrapper.find(`.status-card li.el-dropdown-menu__item`)
|
|
||||||
button.trigger('click')
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports[4].statuses[0].sensitive).toEqual(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('removes sensitive flag to a status', async (done) => {
|
|
||||||
const report = store.state.reports.fetchedReports[4]
|
|
||||||
const wrapper = mount(TimelineItem, {
|
|
||||||
store,
|
|
||||||
localVue,
|
|
||||||
propsData: {
|
|
||||||
report: report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(report.statuses[1].sensitive).toBe(true)
|
|
||||||
|
|
||||||
const button = wrapper.find(`.status-card:nth-child(${2}) li.el-dropdown-menu__item`)
|
|
||||||
button.trigger('click')
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports[4].statuses[1].sensitive).toEqual(false)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('changes status visibility from public to unlisted', async (done) => {
|
|
||||||
const report = store.state.reports.fetchedReports[4]
|
|
||||||
const wrapper = mount(TimelineItem, {
|
|
||||||
store,
|
|
||||||
localVue,
|
|
||||||
propsData: {
|
|
||||||
report: report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(report.statuses[0].visibility).toBe('public')
|
|
||||||
|
|
||||||
const button = wrapper.find(`.status-card li.el-dropdown-menu__item:nth-child(${3})`)
|
|
||||||
button.trigger('click')
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports[4].statuses[0].visibility).toEqual('unlisted')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('changes status visibility from unlisted to private', async (done) => {
|
|
||||||
const report = store.state.reports.fetchedReports[4]
|
|
||||||
const wrapper = mount(TimelineItem, {
|
|
||||||
store,
|
|
||||||
localVue,
|
|
||||||
propsData: {
|
|
||||||
report: report
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(report.statuses[1].visibility).toBe('unlisted')
|
|
||||||
|
|
||||||
const button = wrapper.find(`.status-card:nth-child(${2}) li.el-dropdown-menu__item:nth-child(${3})`)
|
|
||||||
button.trigger('click')
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports[4].statuses[1].visibility).toEqual('private')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('deletes a status', async (done) => {
|
|
||||||
const report = store.state.reports.fetchedReports[4]
|
|
||||||
expect(report.statuses.length).toEqual(2)
|
|
||||||
|
|
||||||
store.dispatch('DeleteStatus', { statusId: '11', reportId: '7'})
|
|
||||||
await flushPromises()
|
|
||||||
expect(store.state.reports.fetchedReports[4].statuses.length).toEqual(1)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
Loading…
Reference in a new issue