From c9e9b62955a3fa26fcdc9a0d28d9b96f6af9baa0 Mon Sep 17 00:00:00 2001 From: Angelina Filippova Date: Wed, 25 Sep 2019 19:08:43 +0300 Subject: [PATCH 01/17] Extract dropdown for moderating users into separate component and rename timeline item to report --- .../components/ModerateUserDropdown.vue | 86 +++++++++++++++++++ .../{TimelineItem.vue => Report.vue} | 74 +--------------- src/views/reports/index.vue | 70 +++++++++++---- test/views/reports/timelineItem.test.js | 16 ++-- 4 files changed, 153 insertions(+), 93 deletions(-) create mode 100644 src/views/reports/components/ModerateUserDropdown.vue rename src/views/reports/components/{TimelineItem.vue => Report.vue} (57%) diff --git a/src/views/reports/components/ModerateUserDropdown.vue b/src/views/reports/components/ModerateUserDropdown.vue new file mode 100644 index 00000000..141b2afe --- /dev/null +++ b/src/views/reports/components/ModerateUserDropdown.vue @@ -0,0 +1,86 @@ + + + diff --git a/src/views/reports/components/TimelineItem.vue b/src/views/reports/components/Report.vue similarity index 57% rename from src/views/reports/components/TimelineItem.vue rename to src/views/reports/components/Report.vue index 771298aa..6d07aded 100644 --- a/src/views/reports/components/TimelineItem.vue +++ b/src/views/reports/components/Report.vue @@ -16,60 +16,7 @@ {{ $t('reports.close') }} - - {{ $t('reports.moderateUser') }} - - - {{ report.account.deactivated ? $t('users.activateAccount') : $t('users.deactivateAccount') }} - - - {{ $t('users.deleteAccount') }} - - - {{ $t('users.forceNsfw') }} - - - - {{ $t('users.stripMedia') }} - - - - {{ $t('users.forceUnlisted') }} - - - - {{ $t('users.sandbox') }} - - - - {{ $t('users.disableRemoteSubscription') }} - - - - {{ $t('users.disableAnySubscription') }} - - - - +
@@ -112,10 +59,11 @@ @@ -56,9 +87,14 @@ export default { padding: 0px; } .filter-container { + display: flex; + flex-direction: column; margin: 22px 15px 22px 15px; padding-bottom: 0 } + .group-reports-checkbox { + margin-top: 10px; + } h1 { margin: 22px 0 0 15px; } @@ -78,9 +114,13 @@ only screen and (max-width: 760px), .filter-container { margin: 0 10px } - .timeline { - margin: 20px 20px 20px 18px - } + } + #app > div > div.main-container > section > div > div.block > ul { + margin: 45px 45px 5px 19px; + } + .reports-pagination { + margin: 25px 0; + text-align: center; } } diff --git a/test/views/reports/timelineItem.test.js b/test/views/reports/timelineItem.test.js index 6e3b9f01..5582732c 100644 --- a/test/views/reports/timelineItem.test.js +++ b/test/views/reports/timelineItem.test.js @@ -1,7 +1,7 @@ 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 Report from '@/views/reports/components/Report' import storeConfig from './store.conf' import { cloneDeep } from 'lodash' import flushPromises from 'flush-promises' @@ -25,7 +25,7 @@ describe('Report in a timeline', () => { it('changes report state from open to resolved', async (done) => { const report = store.state.reports.fetchedReports[0] - const wrapper = mount(TimelineItem, { + const wrapper = mount(Report, { store, localVue, propsData: { @@ -43,7 +43,7 @@ describe('Report in a timeline', () => { it('changes report state from open to closed', async (done) => { const report = store.state.reports.fetchedReports[3] - const wrapper = mount(TimelineItem, { + const wrapper = mount(Report, { store, localVue, propsData: { @@ -61,7 +61,7 @@ describe('Report in a timeline', () => { it('shows statuses', () => { const report = store.state.reports.fetchedReports[4] - const wrapper = mount(TimelineItem, { + const wrapper = mount(Report, { store, localVue, propsData: { @@ -75,7 +75,7 @@ describe('Report in a timeline', () => { it('adds sensitive flag to a status', async (done) => { const report = store.state.reports.fetchedReports[4] - const wrapper = mount(TimelineItem, { + const wrapper = mount(Report, { store, localVue, propsData: { @@ -93,7 +93,7 @@ describe('Report in a timeline', () => { it('removes sensitive flag to a status', async (done) => { const report = store.state.reports.fetchedReports[4] - const wrapper = mount(TimelineItem, { + const wrapper = mount(Report, { store, localVue, propsData: { @@ -111,7 +111,7 @@ describe('Report in a timeline', () => { it('changes status visibility from public to unlisted', async (done) => { const report = store.state.reports.fetchedReports[4] - const wrapper = mount(TimelineItem, { + const wrapper = mount(Report, { store, localVue, propsData: { @@ -129,7 +129,7 @@ describe('Report in a timeline', () => { it('changes status visibility from unlisted to private', async (done) => { const report = store.state.reports.fetchedReports[4] - const wrapper = mount(TimelineItem, { + const wrapper = mount(Report, { store, localVue, propsData: { From 6ccffd97283b4d50b2cc5f8d54c53cd858a4d2f0 Mon Sep 17 00:00:00 2001 From: Angelina Filippova Date: Sat, 28 Sep 2019 01:24:51 +0300 Subject: [PATCH 02/17] Fetch reports after changing and deleting status --- src/store/modules/reports.js | 26 ++++------------- src/views/reports/components/Report.vue | 7 ++++- src/views/reports/components/Statuses.vue | 35 +++++++++++------------ 3 files changed, 27 insertions(+), 41 deletions(-) diff --git a/src/store/modules/reports.js b/src/store/modules/reports.js index a699a22a..8ff3a909 100644 --- a/src/store/modules/reports.js +++ b/src/store/modules/reports.js @@ -28,33 +28,17 @@ const reports = { const updatedReports = state.fetchedReports.map(report => report.id === reportId ? data : report) commit('SET_REPORTS', updatedReports) }, - 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) + async ChangeStatusScope({ dispatch, getters }, { statusId, isSensitive, visibility }) { + await changeStatusScope(statusId, isSensitive, visibility, getters.authHost, getters.token) + dispatch('FetchReports') }, ClearFetchedReports({ commit }) { commit('SET_REPORTS', []) commit('SET_LAST_REPORT_ID', '') }, - async DeleteStatus({ commit, getters, state }, { statusId, reportId }) { + async DeleteStatus({ dispatch, getters }, { statusId }) { 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) + dispatch('FetchReports') }, async FetchReports({ commit, getters, state }) { commit('SET_LOADING', true) diff --git a/src/views/reports/components/Report.vue b/src/views/reports/components/Report.vue index 6d07aded..418284d3 100644 --- a/src/views/reports/components/Report.vue +++ b/src/views/reports/components/Report.vue @@ -49,7 +49,9 @@
- + + +
@@ -87,6 +89,9 @@ export default { return 'primary' } }, + getStatusesTitle(statuses) { + return `Reported statuses: ${statuses.length} item(s)` + }, parseTimestamp(timestamp) { return moment(timestamp).format('L HH:mm') } diff --git a/src/views/reports/components/Statuses.vue b/src/views/reports/components/Statuses.vue index a385a700..c276af90 100644 --- a/src/views/reports/components/Statuses.vue +++ b/src/views/reports/components/Statuses.vue @@ -1,6 +1,6 @@ + + diff --git a/src/views/reports/components/ReportCard.vue b/src/views/reports/components/ReportCard.vue new file mode 100644 index 00000000..62fa1945 --- /dev/null +++ b/src/views/reports/components/ReportCard.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/views/reports/index.vue b/src/views/reports/index.vue index 928e2b2f..f35ab2e3 100644 --- a/src/views/reports/index.vue +++ b/src/views/reports/index.vue @@ -3,12 +3,15 @@

{{ $t('reports.reports') }}

- + Group reports by statuses
- + + + +
@@ -29,14 +32,181 @@ @@ -274,6 +265,10 @@ export default { } } +.reports-pagination { + margin: 25px 0; + text-align: center; +} @media only screen and (max-width: 760px), (min-device-width: 768px) and (max-device-width: 1024px) { @@ -288,9 +283,5 @@ only screen and (max-width: 760px), #app > div > div.main-container > section > div > div.block > ul { margin: 45px 45px 5px 19px; } - .reports-pagination { - margin: 25px 0; - text-align: center; - } } From a0667c1f4552614ca9d968f1a7fcfd4e1d1cfb85 Mon Sep 17 00:00:00 2001 From: Angelina Filippova Date: Mon, 30 Sep 2019 00:22:01 +0300 Subject: [PATCH 08/17] Move report rendering and its pagination inside report component --- src/store/modules/reports.js | 4 +- .../reports/components/GroupedReport.vue | 102 +++++------ src/views/reports/components/Report.vue | 161 +++++++++++------- src/views/reports/index.vue | 38 +---- 4 files changed, 158 insertions(+), 147 deletions(-) diff --git a/src/store/modules/reports.js b/src/store/modules/reports.js index 5d1cdb69..9922f465 100644 --- a/src/store/modules/reports.js +++ b/src/store/modules/reports.js @@ -5,8 +5,8 @@ const reports = { fetchedReports: [], totalReportsCount: 0, currentPage: 1, - pageSize: 1, - groupReports: true, + pageSize: 50, + groupReports: false, stateFilter: '', loading: true }, diff --git a/src/views/reports/components/GroupedReport.vue b/src/views/reports/components/GroupedReport.vue index 1e6cc8fa..f304a87d 100644 --- a/src/views/reports/components/GroupedReport.vue +++ b/src/views/reports/components/GroupedReport.vue @@ -1,55 +1,57 @@ - - diff --git a/src/views/status/Status.vue b/src/views/status/Status.vue new file mode 100644 index 00000000..74bb3881 --- /dev/null +++ b/src/views/status/Status.vue @@ -0,0 +1,171 @@ + + + + + From 2ea990f0743a012e1b334beca14f73b1d8420827 Mon Sep 17 00:00:00 2001 From: Angelina Filippova Date: Fri, 4 Oct 2019 00:20:48 +0300 Subject: [PATCH 11/17] Add module for status --- src/api/reports.js | 19 ------------------- src/api/status.js | 24 ++++++++++++++++++++++++ src/store/index.js | 2 ++ src/store/modules/reports.js | 10 +--------- src/store/modules/status.js | 16 ++++++++++++++++ 5 files changed, 43 insertions(+), 28 deletions(-) create mode 100644 src/api/status.js create mode 100644 src/store/modules/status.js diff --git a/src/api/reports.js b/src/api/reports.js index 9bad8f86..073f84ad 100644 --- a/src/api/reports.js +++ b/src/api/reports.js @@ -12,25 +12,6 @@ export async function changeState(state, id, authHost, token) { }) } -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) - }) -} - 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}` diff --git a/src/api/status.js b/src/api/status.js new file mode 100644 index 00000000..7d931ae0 --- /dev/null +++ b/src/api/status.js @@ -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()}` } : {} diff --git a/src/store/index.js b/src/store/index.js index 830c0788..9a3cad50 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -6,6 +6,7 @@ import invites from './modules/invites' import permission from './modules/permission' import reports from './modules/reports' import settings from './modules/settings' +import status from './modules/status' import tagsView from './modules/tagsView' import user from './modules/user' import userProfile from './modules/userProfile' @@ -23,6 +24,7 @@ const store = new Vuex.Store({ permission, reports, settings, + status, tagsView, user, userProfile, diff --git a/src/store/modules/reports.js b/src/store/modules/reports.js index 9922f465..8e3d2c4f 100644 --- a/src/store/modules/reports.js +++ b/src/store/modules/reports.js @@ -1,4 +1,4 @@ -import { changeState, changeStatusScope, deleteStatus, fetchReports } from '@/api/reports' +import { changeState, fetchReports } from '@/api/reports' const reports = { state: { @@ -38,18 +38,10 @@ const reports = { await changeState(reportState, reportId, getters.authHost, getters.token) dispatch('FetchReports', state.currentPage) }, - async ChangeStatusScope({ dispatch, getters, state }, { statusId, isSensitive, visibility }) { - await changeStatusScope(statusId, isSensitive, visibility, getters.authHost, getters.token) - dispatch('FetchReports', state.currentPage) - }, ClearFetchedReports({ commit }) { commit('SET_REPORTS', []) commit('SET_LAST_REPORT_ID', '') }, - async DeleteStatus({ dispatch, getters, state }, { statusId }) { - await deleteStatus(statusId, getters.authHost, getters.token) - dispatch('FetchReports', state.currentPage) - }, async FetchReports({ commit, getters, state }, page) { commit('SET_LOADING', true) const { data } = await fetchReports(state.stateFilter, page, state.pageSize, getters.authHost, getters.token) diff --git a/src/store/modules/status.js b/src/store/modules/status.js new file mode 100644 index 00000000..a287f94b --- /dev/null +++ b/src/store/modules/status.js @@ -0,0 +1,16 @@ +import { changeStatusScope, deleteStatus } from '@/api/status' + +const status = { + actions: { + async ChangeStatusScope({ dispatch, getters, state }, { statusId, isSensitive, visibility }) { + await changeStatusScope(statusId, isSensitive, visibility, getters.authHost, getters.token) + dispatch('FetchReports', state.currentPage) + }, + async DeleteStatus({ dispatch, getters, state }, { statusId }) { + await deleteStatus(statusId, getters.authHost, getters.token) + dispatch('FetchReports', state.currentPage) + } + } +} + +export default status From f5c088dc1a7ef1df935b15cc310378c1a2686087 Mon Sep 17 00:00:00 2001 From: Angelina Filippova Date: Fri, 4 Oct 2019 00:45:21 +0300 Subject: [PATCH 12/17] Add ability to display media attachments, polls and statuses with hidden content --- src/views/status/Status.vue | 169 ++++++++++++++++++++++++------------ src/views/users/show.vue | 34 ++------ 2 files changed, 118 insertions(+), 85 deletions(-) diff --git a/src/views/status/Status.vue b/src/views/status/Status.vue index 74bb3881..e79b5a80 100644 --- a/src/views/status/Status.vue +++ b/src/views/status/Status.vue @@ -54,7 +54,40 @@
- +
+ {{ status.spoiler_text }} + Show more + Show less +
+ +
+
    +
  • + {{ option.title }} + +
  • +
+
+
+ +
+
+ +
+
+ +
+
    +
  • + {{ option.title }} + +
  • +
+
+
+ +
+
@@ -66,13 +99,18 @@ import moment from 'moment' export default { - name: 'Statuses', + name: 'Status', props: { status: { type: Object, required: true } }, + data() { + return { + showHiddenStatus: false + } + }, methods: { capitalizeFirstLetter(str) { return str.charAt(0).toUpperCase() + str.slice(1) @@ -98,6 +136,13 @@ export default { }) }) }, + 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') } @@ -106,66 +151,78 @@ export default { diff --git a/src/views/users/show.vue b/src/views/users/show.vue index 049ae02f..829f7ebd 100644 --- a/src/views/users/show.vue +++ b/src/views/users/show.vue @@ -70,22 +70,8 @@ - - - {{ status.spoiler_text }} -

-

-
    -
  • - {{ option.title }} - -
  • -
-
-
- -
-
+ +
@@ -94,8 +80,11 @@ + + From f477dec059404698a57a77a98ba01715d9fc4758 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Fri, 15 Nov 2019 12:54:33 +0900 Subject: [PATCH 17/17] Pagination --- CHANGELOG.md | 3 ++- src/api/status.js | 4 ++-- src/lang/en.js | 3 ++- src/store/modules/status.js | 14 ++++++++++++-- src/views/statuses/index.vue | 27 +++++++++++++++++++++++---- 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75553acf..017191a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Emoji pack configuration +- Statuses page: fetch all statuses from a given instance ## [1.1.0] - 2019-09-15 @@ -26,7 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - removes "Dashboard" from dropdown menu - makes all single selects clearable and allow to enter custom values in all multiple selects -- removes legacy activitypub accept_blocks setting +- removes legacy activitypub accept_blocks setting ### Fixed diff --git a/src/api/status.js b/src/api/status.js index 4b62da0b..ab9334e5 100644 --- a/src/api/status.js +++ b/src/api/status.js @@ -21,10 +21,10 @@ export async function deleteStatus(id, authHost, token) { }) } -export async function fetchStatusesByInstance(instance, authHost, token) { +export async function fetchStatusesByInstance(instance, authHost, token, pageSize, page = 1) { return await request({ baseURL: baseName(authHost), - url: `/api/pleroma/admin/instances/${instance}/statuses`, + url: `/api/pleroma/admin/instances/${instance}/statuses?page=${page}&page_size=${pageSize}`, method: 'get', headers: authHeaders(token) }) diff --git a/src/lang/en.js b/src/lang/en.js index f9c56069..396b2127 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -232,7 +232,8 @@ export default { }, statuses: { statuses: 'Statuses', - instanceFilter: 'Instance filter' + instanceFilter: 'Instance filter', + loadMore: 'Load more' }, userProfile: { tags: 'Tags', diff --git a/src/store/modules/status.js b/src/store/modules/status.js index a1a864b3..2a02bd70 100644 --- a/src/store/modules/status.js +++ b/src/store/modules/status.js @@ -9,6 +9,9 @@ const status = { SET_STATUSES: (state, statuses) => { state.fetchedStatuses = statuses }, + PUSH_STATUSES: (state, statuses) => { + state.fetchedStatuses = [...state.fetchedStatuses, ...statuses] + }, SET_LOADING: (state, status) => { state.loading = status } @@ -30,12 +33,19 @@ const status = { dispatch('FetchUserStatuses', { userId, godmode }) } }, - async FetchStatusesByInstance({ commit, getters }, instance) { + async FetchStatusesByInstance({ commit, getters }, { instance, page, pageSize }) { commit('SET_LOADING', true) - const statuses = await fetchStatusesByInstance(instance, getters.authHost, getters.token) + const statuses = await fetchStatusesByInstance(instance, getters.authHost, getters.token, pageSize, page) commit('SET_STATUSES', statuses.data) commit('SET_LOADING', false) + }, + async FetchStatusesPageByInstance({ commit, getters }, { instance, page, pageSize }) { + commit('SET_LOADING', true) + const statuses = await fetchStatusesByInstance(instance, getters.authHost, getters.token, pageSize, page) + + commit('PUSH_STATUSES', statuses.data) + commit('SET_LOADING', false) } } } diff --git a/src/views/statuses/index.vue b/src/views/statuses/index.vue index adf56052..bcc98ac4 100644 --- a/src/views/statuses/index.vue +++ b/src/views/statuses/index.vue @@ -1,5 +1,5 @@ @@ -28,11 +31,12 @@ export default { data() { return { selectedInstance: '', - page: 1 + page: 1, + pageSize: 2 } }, computed: { - loading() { + loadingPeers() { return this.$store.state.peers.loading }, ...mapGetters([ @@ -47,7 +51,18 @@ export default { }, methods: { handleFilterChange(instance) { - this.$store.dispatch('FetchStatusesByInstance', instance) + this.page = 1 + + this.$store.dispatch('FetchStatusesByInstance', { instance, page: this.page, pageSize: this.pageSize }) + }, + handleLoadMore() { + this.page = this.page + 1 + + this.$store.dispatch('FetchStatusesPageByInstance', { + instance: this.selectedInstance, + page: this.page, + pageSize: this.pageSize + }) } } } @@ -60,6 +75,10 @@ export default { .filter-container { margin: 22px 15px 15px 0; } +.statuses-pagination { + padding: 15px 0; + text-align: center; +} h1 { margin: 22px 0 0 0; }