forked from AkkomaGang/admin-fe
Merge branch 'develop' into 'feature/do-not-show-users-with-null-nicknames'
# Conflicts: # src/components/Status/index.vue # src/views/users/components/ModerationDropdown.vue # src/views/users/show.vue
This commit is contained in:
commit
12bac96c9d
19 changed files with 757 additions and 191 deletions
|
@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Create `/statuses/:id` route that shows single status
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Statuses count changes when an instance is selected and shows the amount of statuses from an originating instance
|
- Statuses count changes when an instance is selected and shows the amount of statuses from an originating instance
|
||||||
|
@ -18,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Send `true` and `false` as booleans if they are values of single selects on the Settings page
|
- Send `true` and `false` as booleans if they are values of single selects on the Settings page
|
||||||
|
- Fix sorting users on Users page if there is an acount with missing nickname or ID
|
||||||
|
|
||||||
## [2.0.3] - 2020-04-29
|
## [2.0.3] - 2020-04-29
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,29 @@ export async function deleteStatus(id, authHost, token) {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchStatus(id, authHost, token) {
|
||||||
|
const data = {
|
||||||
|
account: {
|
||||||
|
id: '9n1bySks25olxWrku0',
|
||||||
|
avatar: 'http://localhost:4000/images/avi.png',
|
||||||
|
display_name: 'dolin',
|
||||||
|
tags: ['strip_media', 'sandbox', 'disable_any_subscription', 'force_nsfw'],
|
||||||
|
url: 'http://localhost:4000/users/dolin'
|
||||||
|
},
|
||||||
|
content: 'pizza makes everything better',
|
||||||
|
created_at: '2020-05-22T17:34:34.000Z',
|
||||||
|
id: '9vJOO3iFPyjNaEhJ5s',
|
||||||
|
media_attachments: [],
|
||||||
|
poll: null,
|
||||||
|
sensitive: false,
|
||||||
|
spoiler_text: '',
|
||||||
|
visibility: 'public',
|
||||||
|
url: 'http://localhost:4000/notice/9vJOO3iFPyjNaEhJ5s'
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve({ data })
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchStatusesByInstance({ instance, authHost, token, pageSize, page }) {
|
export async function fetchStatusesByInstance({ instance, authHost, token, pageSize, page }) {
|
||||||
let data
|
let data
|
||||||
if (pageSize === 1) {
|
if (pageSize === 1) {
|
||||||
|
|
|
@ -6,7 +6,11 @@ export let users = [
|
||||||
|
|
||||||
const userProfile = { avatar: 'avatar.jpg', nickname: 'allis', id: '2', tags: [], roles: { admin: true, moderator: false }, local: true, external: false }
|
const userProfile = { avatar: 'avatar.jpg', nickname: 'allis', id: '2', tags: [], roles: { admin: true, moderator: false }, local: true, external: false }
|
||||||
|
|
||||||
const userStatuses = []
|
const userStatuses = [
|
||||||
|
{ account: { id: '9n1bySks25olxWrku0', display_name: 'dolin' }, content: 'pizza makes everything better', id: '9vJOO3iFPyjNaEhJ5s', created_at: '2020-05-22T17:34:34.000Z', visibility: 'public' },
|
||||||
|
{ account: { id: '9n1bySks25olxWrku0', display_name: 'dolin' }, content: 'pizza time', id: '9vJPD5XKOdzQ0bvGLY', created_at: '2020-05-22T17:34:34.000Z', visibility: 'public' },
|
||||||
|
{ account: { id: '9n1bySks25olxWrku0', display_name: 'dolin' }, content: 'what is yout favorite pizza?', id: '9jop82OBXeFPYulVjM', created_at: '2020-05-22T17:34:34.000Z', visibility: 'public' }
|
||||||
|
]
|
||||||
|
|
||||||
const filterUsers = (str) => {
|
const filterUsers = (str) => {
|
||||||
const filters = str.split(',').filter(item => item.length > 0)
|
const filters = str.split(',').filter(item => item.length > 0)
|
||||||
|
|
|
@ -21,6 +21,15 @@ export async function deleteStatus(id, authHost, token) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchStatus(id, authHost, token) {
|
||||||
|
return await request({
|
||||||
|
baseURL: baseName(authHost),
|
||||||
|
url: `/api/pleroma/admin/statuses/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
headers: authHeaders(token)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchStatuses({ godmode, localOnly, authHost, token, pageSize, page }) {
|
export async function fetchStatuses({ godmode, localOnly, authHost, token, pageSize, page }) {
|
||||||
return await request({
|
return await request({
|
||||||
baseURL: baseName(authHost),
|
baseURL: baseName(authHost),
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<el-card v-if="!status.deleted" class="status-card" @click.native="handleRouteChange()">
|
||||||
<el-card v-if="!status.deleted" class="status-card">
|
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
<div class="status-header">
|
<div class="status-header">
|
||||||
<div class="status-account-container">
|
<div class="status-account-container">
|
||||||
<div class="status-account">
|
<div class="status-account">
|
||||||
<el-checkbox v-if="showCheckbox" class="status-checkbox" @change="handleStatusSelection(account)"/>
|
<el-checkbox v-if="showCheckbox" class="status-checkbox" @change="handleStatusSelection(account)"/>
|
||||||
|
<router-link v-if="propertyExists(account, 'id')" :to="{ name: 'UsersShow', params: { id: account.id }}" @click.native.stop>
|
||||||
|
<div class="status-card-header">
|
||||||
<img v-if="propertyExists(account, 'avatar')" :src="account.avatar" class="status-avatar-img">
|
<img v-if="propertyExists(account, 'avatar')" :src="account.avatar" class="status-avatar-img">
|
||||||
<a v-if="propertyExists(account, 'url', 'nickname')" :href="account.url" target="_blank" class="account">
|
<span v-if="propertyExists(account, 'nickname')" class="status-account-name">{{ account.nickname }}</span>
|
||||||
<span class="status-account-name">{{ account.nickname }}</span>
|
|
||||||
</a>
|
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<span v-if="propertyExists(account, 'nickname')" class="status-account-name">
|
<span v-if="propertyExists(account, 'nickname')" class="status-account-name">
|
||||||
{{ account.nickname }}
|
{{ account.nickname }}
|
||||||
|
@ -17,11 +16,15 @@
|
||||||
<span v-else class="status-account-name deactivated">({{ $t('users.invalidNickname') }})</span>
|
<span v-else class="status-account-name deactivated">({{ $t('users.invalidNickname') }})</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-actions">
|
<div class="status-actions">
|
||||||
|
<div class="status-tags">
|
||||||
<el-tag v-if="status.sensitive" type="warning" size="large">{{ $t('reports.sensitive') }}</el-tag>
|
<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-tag size="large">{{ capitalizeFirstLetter(status.visibility) }}</el-tag>
|
||||||
<el-dropdown trigger="click">
|
</div>
|
||||||
|
<el-dropdown trigger="click" @click.native.stop>
|
||||||
<el-button plain size="small" icon="el-icon-edit" class="status-actions-button">
|
<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"/>
|
{{ $t('reports.changeScope') }}<i class="el-icon-arrow-down el-icon--right"/>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
@ -94,10 +97,14 @@
|
||||||
<img :src="attachment.preview_url">
|
<img :src="attachment.preview_url">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a :href="status.url" target="_blank" class="account">
|
<div class="status-footer">
|
||||||
{{ parseTimestamp(status.created_at) }}
|
<span class="status-created-at">{{ parseTimestamp(status.created_at) }}</span>
|
||||||
|
<a v-if="status.url" :href="status.url" target="_blank" class="account" @click.stop>
|
||||||
|
Open status in instance
|
||||||
|
<i class="el-icon-top-right"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card v-else class="status-card">
|
<el-card v-else class="status-card">
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
|
@ -113,11 +120,14 @@
|
||||||
<span v-if="status.content" class="status-content" v-html="status.content"/>
|
<span v-if="status.content" class="status-content" v-html="status.content"/>
|
||||||
<span v-else class="status-without-content">no content</span>
|
<span v-else class="status-without-content">no content</span>
|
||||||
</div>
|
</div>
|
||||||
<a v-if="status.created_at" :href="status.url" target="_blank" class="account">
|
<div class="status-footer">
|
||||||
{{ parseTimestamp(status.created_at) }}
|
<span v-if="status.created_at" class="status-created-at">{{ parseTimestamp(status.created_at) }}</span>
|
||||||
|
<a v-if="status.url" :href="status.url" target="_blank" class="account" @click.stop>
|
||||||
|
Open status in instance
|
||||||
|
<i class="el-icon-top-right"/>
|
||||||
</a>
|
</a>
|
||||||
</el-card>
|
|
||||||
</div>
|
</div>
|
||||||
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -208,6 +218,9 @@ export default {
|
||||||
handleStatusSelection(account) {
|
handleStatusSelection(account) {
|
||||||
this.$emit('status-selection', account)
|
this.$emit('status-selection', account)
|
||||||
},
|
},
|
||||||
|
handleRouteChange() {
|
||||||
|
this.$router.push({ name: 'StatusShow', params: { id: this.status.id }})
|
||||||
|
},
|
||||||
optionPercent(poll, pollOption) {
|
optionPercent(poll, pollOption) {
|
||||||
const allVotes = poll.options.reduce((acc, option) => (acc + option.votes_count), 0)
|
const allVotes = poll.options.reduce((acc, option) => (acc + option.votes_count), 0)
|
||||||
if (allVotes === 0) {
|
if (allVotes === 0) {
|
||||||
|
@ -231,10 +244,14 @@ export default {
|
||||||
<style rel='stylesheet/scss' lang='scss'>
|
<style rel='stylesheet/scss' lang='scss'>
|
||||||
.status-card {
|
.status-card {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
cursor: pointer;
|
||||||
.account {
|
.account {
|
||||||
text-decoration: underline;
|
|
||||||
line-height: 26px;
|
line-height: 26px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
.account:hover {
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
.deactivated {
|
.deactivated {
|
||||||
color: gray;
|
color: gray;
|
||||||
|
@ -271,6 +288,10 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
.status-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
.status-checkbox {
|
.status-checkbox {
|
||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
}
|
}
|
||||||
|
@ -278,13 +299,26 @@ export default {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 26px;
|
line-height: 26px;
|
||||||
}
|
}
|
||||||
|
.status-created-at {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
.status-deleted {
|
.status-deleted {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
}
|
}
|
||||||
|
.status-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
.status-header {
|
.status-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.status-tags {
|
||||||
|
display: inline;
|
||||||
}
|
}
|
||||||
.status-without-content {
|
.status-without-content {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
@ -303,7 +337,7 @@ export default {
|
||||||
padding: 10px 17px;
|
padding: 10px 17px;
|
||||||
}
|
}
|
||||||
.el-tag {
|
.el-tag {
|
||||||
margin: 3px 4px 3px 0;
|
margin: 3px 0;
|
||||||
}
|
}
|
||||||
.status-account-container {
|
.status-account-container {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
@ -312,12 +346,20 @@ export default {
|
||||||
margin: 3px 0 3px;
|
margin: 3px 0 3px;
|
||||||
}
|
}
|
||||||
.status-actions {
|
.status-actions {
|
||||||
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.status-footer {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
.status-header {
|
.status-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,16 +171,16 @@ export default {
|
||||||
id: 'ID',
|
id: 'ID',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
status: 'Status',
|
status: 'Status',
|
||||||
local: 'local',
|
local: 'Local',
|
||||||
external: 'external',
|
external: 'External',
|
||||||
deactivated: 'deactivated',
|
deactivated: 'Deactivated',
|
||||||
active: 'active',
|
active: 'Active',
|
||||||
unconfirmed: 'unconfirmed',
|
unconfirmed: 'Unconfirmed',
|
||||||
actions: 'Actions',
|
actions: 'Actions',
|
||||||
activate: 'Activate',
|
activate: 'Activate',
|
||||||
deactivate: 'Deactivate',
|
deactivate: 'Deactivate',
|
||||||
admin: 'admin',
|
admin: 'Admin',
|
||||||
moderator: 'moderator',
|
moderator: 'Moderator',
|
||||||
moderation: 'Moderation',
|
moderation: 'Moderation',
|
||||||
revokeAdmin: 'Revoke Admin',
|
revokeAdmin: 'Revoke Admin',
|
||||||
grantAdmin: 'Grant Admin',
|
grantAdmin: 'Grant Admin',
|
||||||
|
@ -205,8 +205,8 @@ export default {
|
||||||
moderateUser: 'Moderate user',
|
moderateUser: 'Moderate user',
|
||||||
moderateUsers: 'Moderate multiple users',
|
moderateUsers: 'Moderate multiple users',
|
||||||
createAccount: 'Create new account',
|
createAccount: 'Create new account',
|
||||||
apply: 'apply',
|
apply: 'Apply',
|
||||||
remove: 'remove',
|
remove: 'Remove',
|
||||||
grantRightConfirmation: 'Are you sure you want to grant {right} rights to all selected users?',
|
grantRightConfirmation: 'Are you sure you want to grant {right} rights to all selected users?',
|
||||||
revokeRightConfirmation: 'Are you sure you want to revoke {right} rights from all selected users?',
|
revokeRightConfirmation: 'Are you sure you want to revoke {right} rights from all selected users?',
|
||||||
activateMultipleUsersConfirmation: 'Are you sure you want to activate accounts of all selected users?',
|
activateMultipleUsersConfirmation: 'Are you sure you want to activate accounts of all selected users?',
|
||||||
|
@ -258,15 +258,15 @@ export default {
|
||||||
tags: 'Tags',
|
tags: 'Tags',
|
||||||
moderator: 'Moderator',
|
moderator: 'Moderator',
|
||||||
admin: 'Admin',
|
admin: 'Admin',
|
||||||
local: 'local',
|
local: 'Local',
|
||||||
external: 'external',
|
external: 'External',
|
||||||
localUppercase: 'Local',
|
accountType: 'Account type',
|
||||||
nickname: 'Nickname',
|
nickname: 'Nickname',
|
||||||
recentStatuses: 'Recent Statuses',
|
recentStatuses: 'Recent Statuses',
|
||||||
roles: 'Roles',
|
roles: 'Roles',
|
||||||
activeUppercase: 'Active',
|
active: 'Active',
|
||||||
active: 'active',
|
status: 'Status',
|
||||||
deactivated: 'deactivated',
|
deactivated: 'Deactivated',
|
||||||
noStatuses: 'No statuses to show',
|
noStatuses: 'No statuses to show',
|
||||||
securitySettings: {
|
securitySettings: {
|
||||||
email: 'Email',
|
email: 'Email',
|
||||||
|
@ -286,7 +286,7 @@ export default {
|
||||||
},
|
},
|
||||||
usersFilter: {
|
usersFilter: {
|
||||||
inputPlaceholder: 'Select filter',
|
inputPlaceholder: 'Select filter',
|
||||||
byUserType: 'By user type',
|
byAccountType: 'By account type',
|
||||||
local: 'Local',
|
local: 'Local',
|
||||||
external: 'External',
|
external: 'External',
|
||||||
byStatus: 'By status',
|
byStatus: 'By status',
|
||||||
|
|
|
@ -172,5 +172,17 @@ export const asyncRouterMap = [
|
||||||
],
|
],
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/statuses/:id',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: 'StatusShow',
|
||||||
|
component: () => import('@/views/statuses/show')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
{ path: '*', redirect: '/404', hidden: true }
|
{ path: '*', redirect: '/404', hidden: true }
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import { changeStatusScope, deleteStatus, fetchStatuses, fetchStatusesCount, fetchStatusesByInstance } from '@/api/status'
|
import { changeStatusScope, deleteStatus, fetchStatus, fetchStatuses, fetchStatusesCount, fetchStatusesByInstance } from '@/api/status'
|
||||||
|
|
||||||
const status = {
|
const status = {
|
||||||
state: {
|
state: {
|
||||||
|
fetchedStatus: {},
|
||||||
fetchedStatuses: [],
|
fetchedStatuses: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
|
statusAuthor: {},
|
||||||
statusesByInstance: {
|
statusesByInstance: {
|
||||||
selectedInstance: '',
|
selectedInstance: '',
|
||||||
showLocal: false,
|
showLocal: false,
|
||||||
|
@ -28,6 +30,9 @@ const status = {
|
||||||
CHANGE_SELECTED_INSTANCE: (state, instance) => {
|
CHANGE_SELECTED_INSTANCE: (state, instance) => {
|
||||||
state.statusesByInstance.selectedInstance = instance
|
state.statusesByInstance.selectedInstance = instance
|
||||||
},
|
},
|
||||||
|
SET_STATUS: (state, status) => {
|
||||||
|
state.fetchedStatus = status
|
||||||
|
},
|
||||||
SET_STATUSES_BY_INSTANCE: (state, statuses) => {
|
SET_STATUSES_BY_INSTANCE: (state, statuses) => {
|
||||||
state.fetchedStatuses = statuses
|
state.fetchedStatuses = statuses
|
||||||
},
|
},
|
||||||
|
@ -45,6 +50,9 @@ const status = {
|
||||||
},
|
},
|
||||||
SET_STATUS_VISIBILITY: (state, visibility) => {
|
SET_STATUS_VISIBILITY: (state, visibility) => {
|
||||||
state.statusVisibility = visibility
|
state.statusVisibility = visibility
|
||||||
|
},
|
||||||
|
SET_STATUS_AUTHOR: (state, user) => {
|
||||||
|
state.statusAuthor = user
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -56,6 +64,8 @@ const status = {
|
||||||
dispatch('FetchUserStatuses', { userId, godmode })
|
dispatch('FetchUserStatuses', { userId, godmode })
|
||||||
} else if (fetchStatusesByInstance) { // called from Statuses by Instance
|
} else if (fetchStatusesByInstance) { // called from Statuses by Instance
|
||||||
dispatch('FetchStatusesByInstance')
|
dispatch('FetchStatusesByInstance')
|
||||||
|
} else { // called from Status show page
|
||||||
|
dispatch('FetchStatusAfterUserModeration', statusId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ClearState({ commit }) {
|
ClearState({ commit }) {
|
||||||
|
@ -76,6 +86,21 @@ const status = {
|
||||||
dispatch('FetchStatusesByInstance')
|
dispatch('FetchStatusesByInstance')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async FetchStatus({ commit, dispatch, getters, state }, id) {
|
||||||
|
commit('SET_LOADING', true)
|
||||||
|
const status = await fetchStatus(id, getters.authHost, getters.token)
|
||||||
|
|
||||||
|
commit('SET_STATUS', status.data)
|
||||||
|
commit('SET_STATUS_AUTHOR', status.data.account)
|
||||||
|
commit('SET_LOADING', false)
|
||||||
|
dispatch('FetchUserStatuses', { userId: state.fetchedStatus.account.id, godmode: false })
|
||||||
|
},
|
||||||
|
FetchStatusAfterUserModeration({ commit, dispatch, getters, state }, id) {
|
||||||
|
commit('SET_LOADING', true)
|
||||||
|
fetchStatus(id, getters.authHost, getters.token)
|
||||||
|
.then(status => dispatch('SetStatus', status.data))
|
||||||
|
commit('SET_LOADING', false)
|
||||||
|
},
|
||||||
async FetchStatusesCount({ commit, getters }, instance) {
|
async FetchStatusesCount({ commit, getters }, instance) {
|
||||||
commit('SET_LOADING', true)
|
commit('SET_LOADING', true)
|
||||||
const { data } = await fetchStatusesCount(instance, getters.authHost, getters.token)
|
const { data } = await fetchStatusesCount(instance, getters.authHost, getters.token)
|
||||||
|
@ -159,6 +184,10 @@ const status = {
|
||||||
},
|
},
|
||||||
HandlePageChange({ commit }, page) {
|
HandlePageChange({ commit }, page) {
|
||||||
commit('CHANGE_PAGE', page)
|
commit('CHANGE_PAGE', page)
|
||||||
|
},
|
||||||
|
SetStatus({ commit }, status) {
|
||||||
|
commit('SET_STATUS', status)
|
||||||
|
commit('SET_STATUS_AUTHOR', status.account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,18 +35,21 @@ const userProfile = {
|
||||||
|
|
||||||
dispatch('FetchUserStatuses', { userId, godmode })
|
dispatch('FetchUserStatuses', { userId, godmode })
|
||||||
},
|
},
|
||||||
async FetchUserStatuses({ commit, getters }, { userId, godmode }) {
|
FetchUserStatuses({ commit, dispatch, getters }, { userId, godmode }) {
|
||||||
commit('SET_STATUSES_LOADING', true)
|
commit('SET_STATUSES_LOADING', true)
|
||||||
|
|
||||||
const statuses = await fetchUserStatuses(userId, getters.authHost, godmode, getters.token)
|
fetchUserStatuses(userId, getters.authHost, godmode, getters.token)
|
||||||
|
.then(statuses => dispatch('SetStatuses', statuses.data))
|
||||||
|
|
||||||
commit('SET_STATUSES', statuses.data)
|
|
||||||
commit('SET_STATUSES_LOADING', false)
|
commit('SET_STATUSES_LOADING', false)
|
||||||
},
|
},
|
||||||
async FetchUserCredentials({ commit, getters }, { nickname }) {
|
async FetchUserCredentials({ commit, getters }, { nickname }) {
|
||||||
const userResponse = await fetchUserCredentials(nickname, getters.authHost, getters.token)
|
const userResponse = await fetchUserCredentials(nickname, getters.authHost, getters.token)
|
||||||
commit('SET_USER_CREDENTIALS', userResponse.data)
|
commit('SET_USER_CREDENTIALS', userResponse.data)
|
||||||
},
|
},
|
||||||
|
SetStatuses({ commit }, statuses) {
|
||||||
|
commit('SET_STATUSES', statuses)
|
||||||
|
},
|
||||||
async UpdateUserCredentials({ dispatch, getters }, { nickname, credentials }) {
|
async UpdateUserCredentials({ dispatch, getters }, { nickname, credentials }) {
|
||||||
await updateUserCredentials(nickname, credentials, getters.authHost, getters.token)
|
await updateUserCredentials(nickname, credentials, getters.authHost, getters.token)
|
||||||
dispatch('FetchUserCredentials', { nickname })
|
dispatch('FetchUserCredentials', { nickname })
|
||||||
|
|
|
@ -24,6 +24,7 @@ const users = {
|
||||||
searchQuery: '',
|
searchQuery: '',
|
||||||
totalUsersCount: 0,
|
totalUsersCount: 0,
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
|
pageSize: 50,
|
||||||
filters: {
|
filters: {
|
||||||
local: false,
|
local: false,
|
||||||
external: false,
|
external: false,
|
||||||
|
@ -75,9 +76,6 @@ const users = {
|
||||||
},
|
},
|
||||||
SET_USERS_FILTERS: (state, filters) => {
|
SET_USERS_FILTERS: (state, filters) => {
|
||||||
state.filters = filters
|
state.filters = filters
|
||||||
},
|
|
||||||
SET_USER_PROFILE: (state, user) => {
|
|
||||||
state.userProfile = user
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -90,7 +88,7 @@ const users = {
|
||||||
|
|
||||||
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
||||||
},
|
},
|
||||||
async ApplyChanges({ commit, dispatch, state }, { updatedUsers, callApiFn, userId }) {
|
async ApplyChanges({ commit, dispatch, state }, { updatedUsers, callApiFn, userId, statusId }) {
|
||||||
commit('SWAP_USERS', updatedUsers)
|
commit('SWAP_USERS', updatedUsers)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -100,29 +98,30 @@ const users = {
|
||||||
} finally {
|
} finally {
|
||||||
dispatch('SearchUsers', { query: state.searchQuery, page: state.currentPage })
|
dispatch('SearchUsers', { query: state.searchQuery, page: state.currentPage })
|
||||||
}
|
}
|
||||||
|
if (statusId) {
|
||||||
if (userId) {
|
dispatch('FetchStatusAfterUserModeration', statusId)
|
||||||
|
} else if (userId) {
|
||||||
dispatch('FetchUserProfile', { userId, godmode: false })
|
dispatch('FetchUserProfile', { userId, godmode: false })
|
||||||
}
|
}
|
||||||
dispatch('SuccessMessage')
|
dispatch('SuccessMessage')
|
||||||
},
|
},
|
||||||
async AddRight({ dispatch, getters }, { users, right, _userId }) {
|
async AddRight({ dispatch, getters }, { users, right, _userId, _statusId }) {
|
||||||
const updatedUsers = users.map(user => {
|
const updatedUsers = users.map(user => {
|
||||||
return user.local ? { ...user, roles: { ...user.roles, [right]: true }} : user
|
return user.local ? { ...user, roles: { ...user.roles, [right]: true }} : user
|
||||||
})
|
})
|
||||||
const nicknames = users.map(user => user.nickname)
|
const nicknames = users.map(user => user.nickname)
|
||||||
const callApiFn = async() => await addRight(nicknames, right, getters.authHost, getters.token)
|
const callApiFn = async() => await addRight(nicknames, right, getters.authHost, getters.token)
|
||||||
|
|
||||||
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
|
||||||
},
|
},
|
||||||
async AddTag({ dispatch, getters }, { users, tag, _userId }) {
|
async AddTag({ dispatch, getters }, { users, tag, _userId, _statusId }) {
|
||||||
const updatedUsers = users.map(user => {
|
const updatedUsers = users.map(user => {
|
||||||
return { ...user, tags: [...user.tags, tag] }
|
return { ...user, tags: [...user.tags, tag] }
|
||||||
})
|
})
|
||||||
const nicknames = users.map(user => user.nickname)
|
const nicknames = users.map(user => user.nickname)
|
||||||
const callApiFn = async() => await tagUser(nicknames, [tag], getters.authHost, getters.token)
|
const callApiFn = async() => await tagUser(nicknames, [tag], getters.authHost, getters.token)
|
||||||
|
|
||||||
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
|
||||||
},
|
},
|
||||||
ClearUsersState({ commit }) {
|
ClearUsersState({ commit }) {
|
||||||
commit('SET_SEARCH_QUERY', '')
|
commit('SET_SEARCH_QUERY', '')
|
||||||
|
@ -151,14 +150,14 @@ const users = {
|
||||||
|
|
||||||
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
||||||
},
|
},
|
||||||
async ConfirmUsersEmail({ dispatch, getters }, { users, _userId }) {
|
async ConfirmUsersEmail({ dispatch, getters }, { users, _userId, _statusId }) {
|
||||||
const updatedUsers = users.map(user => {
|
const updatedUsers = users.map(user => {
|
||||||
return { ...user, confirmation_pending: false }
|
return { ...user, confirmation_pending: false }
|
||||||
})
|
})
|
||||||
const nicknames = users.map(user => user.nickname)
|
const nicknames = users.map(user => user.nickname)
|
||||||
const callApiFn = async() => await confirmUserEmail(nicknames, getters.authHost, getters.token)
|
const callApiFn = async() => await confirmUserEmail(nicknames, getters.authHost, getters.token)
|
||||||
|
|
||||||
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
|
||||||
},
|
},
|
||||||
async ResendConfirmationEmail({ dispatch, getters }, users) {
|
async ResendConfirmationEmail({ dispatch, getters }, users) {
|
||||||
const usersNicknames = users.map(user => user.nickname)
|
const usersNicknames = users.map(user => user.nickname)
|
||||||
|
@ -169,14 +168,14 @@ const users = {
|
||||||
}
|
}
|
||||||
dispatch('SuccessMessage')
|
dispatch('SuccessMessage')
|
||||||
},
|
},
|
||||||
async DeleteRight({ dispatch, getters }, { users, right, _userId }) {
|
async DeleteRight({ dispatch, getters }, { users, right, _userId, _statusId }) {
|
||||||
const updatedUsers = users.map(user => {
|
const updatedUsers = users.map(user => {
|
||||||
return user.local ? { ...user, roles: { ...user.roles, [right]: false }} : user
|
return user.local ? { ...user, roles: { ...user.roles, [right]: false }} : user
|
||||||
})
|
})
|
||||||
const nicknames = users.map(user => user.nickname)
|
const nicknames = users.map(user => user.nickname)
|
||||||
const callApiFn = async() => await deleteRight(nicknames, right, getters.authHost, getters.token)
|
const callApiFn = async() => await deleteRight(nicknames, right, getters.authHost, getters.token)
|
||||||
|
|
||||||
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
|
||||||
},
|
},
|
||||||
async DeleteUsers({ commit, dispatch, getters, state }, { users, _userId }) {
|
async DeleteUsers({ commit, dispatch, getters, state }, { users, _userId }) {
|
||||||
const usersNicknames = users.map(user => user.nickname)
|
const usersNicknames = users.map(user => user.nickname)
|
||||||
|
@ -206,14 +205,14 @@ const users = {
|
||||||
RemovePasswordToken({ commit }) {
|
RemovePasswordToken({ commit }) {
|
||||||
commit('SET_PASSWORD_RESET_TOKEN', { link: '', token: '' })
|
commit('SET_PASSWORD_RESET_TOKEN', { link: '', token: '' })
|
||||||
},
|
},
|
||||||
async RemoveTag({ dispatch, getters }, { users, tag, _userId }) {
|
async RemoveTag({ dispatch, getters }, { users, tag, _userId, _statusId }) {
|
||||||
const updatedUsers = users.map(user => {
|
const updatedUsers = users.map(user => {
|
||||||
return { ...user, tags: user.tags.filter(userTag => userTag !== tag) }
|
return { ...user, tags: user.tags.filter(userTag => userTag !== tag) }
|
||||||
})
|
})
|
||||||
const nicknames = users.map(user => user.nickname)
|
const nicknames = users.map(user => user.nickname)
|
||||||
const callApiFn = async() => await untagUser(nicknames, [tag], getters.authHost, getters.token)
|
const callApiFn = async() => await untagUser(nicknames, [tag], getters.authHost, getters.token)
|
||||||
|
|
||||||
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId })
|
dispatch('ApplyChanges', { updatedUsers, callApiFn, userId: _userId, statusId: _statusId })
|
||||||
},
|
},
|
||||||
async RequirePasswordReset({ dispatch, getters }, users) {
|
async RequirePasswordReset({ dispatch, getters }, users) {
|
||||||
const nicknames = users.map(user => user.nickname)
|
const nicknames = users.map(user => user.nickname)
|
||||||
|
|
273
src/views/statuses/show.vue
Normal file
273
src/views/statuses/show.vue
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="!loading" class="status-show-container">
|
||||||
|
<header v-if="isDesktop || isTablet" class="user-page-header">
|
||||||
|
<div class="avatar-name-container">
|
||||||
|
<router-link :to="{ name: 'UsersShow', params: { id: user.id }}">
|
||||||
|
<div class="avatar-name-header">
|
||||||
|
<el-avatar v-if="accountExists(user, 'avatar')" :src="user.avatar" size="large" />
|
||||||
|
<h1 v-if="accountExists(user, 'display_name')">{{ user.display_name }}</h1>
|
||||||
|
</div>
|
||||||
|
</router-link>
|
||||||
|
<a v-if="accountExists(user, 'url')" :href="user.url" target="_blank" class="account">
|
||||||
|
<i class="el-icon-top-right" title="Open user in instance"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="left-header-container">
|
||||||
|
<moderation-dropdown
|
||||||
|
:user="user"
|
||||||
|
:page="'statusPage'"
|
||||||
|
:status-id="status.id"
|
||||||
|
@open-reset-token-dialog="openResetPasswordDialog"/>
|
||||||
|
<reboot-button/>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div v-if="isMobile" class="status-page-header-container">
|
||||||
|
<header class="user-page-header">
|
||||||
|
<div class="avatar-name-container">
|
||||||
|
<el-avatar v-if="accountExists(user, 'avatar')" :src="user.avatar" size="large" />
|
||||||
|
<h1 v-if="accountExists(user, 'display_name')">{{ user.display_name }}</h1>
|
||||||
|
</div>
|
||||||
|
<reboot-button/>
|
||||||
|
</header>
|
||||||
|
<moderation-dropdown
|
||||||
|
:user="user"
|
||||||
|
:page="'userPage'"
|
||||||
|
@open-reset-token-dialog="openResetPasswordDialog"/>
|
||||||
|
</div>
|
||||||
|
<reset-password-dialog
|
||||||
|
:reset-password-dialog-open="resetPasswordDialogOpen"
|
||||||
|
@close-reset-token-dialog="closeResetPasswordDialog"/>
|
||||||
|
<div class="status-container">
|
||||||
|
<status :status="status" :account="user" :show-checkbox="false" :godmode="showPrivate"/>
|
||||||
|
</div>
|
||||||
|
<div class="recent-statuses-container-show">
|
||||||
|
<h2 class="recent-statuses">{{ $t('userProfile.recentStatuses') }} by {{ user.display_name }}</h2>
|
||||||
|
<el-checkbox v-model="showPrivate" class="show-private-statuses" @change="onTogglePrivate">
|
||||||
|
{{ $t('statuses.showPrivateStatuses') }}
|
||||||
|
</el-checkbox>
|
||||||
|
<el-timeline v-if="!statusesLoading" class="statuses">
|
||||||
|
<el-timeline-item v-for="status in statuses" :key="status.id">
|
||||||
|
<status :status="status" :account="status.account" :show-checkbox="false" :user-id="user.id" :godmode="showPrivate"/>
|
||||||
|
</el-timeline-item>
|
||||||
|
<p v-if="statuses.length === 0" class="no-statuses">{{ $t('userProfile.noStatuses') }}</p>
|
||||||
|
</el-timeline>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Status from '@/components/Status'
|
||||||
|
import ModerationDropdown from '../users/components/ModerationDropdown'
|
||||||
|
import RebootButton from '@/components/RebootButton'
|
||||||
|
import ResetPasswordDialog from '@/views/users/components/ResetPasswordDialog'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'StatusShow',
|
||||||
|
components: { ModerationDropdown, RebootButton, ResetPasswordDialog, Status },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showPrivate: false,
|
||||||
|
resetPasswordDialogOpen: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isDesktop() {
|
||||||
|
return this.$store.state.app.device === 'desktop'
|
||||||
|
},
|
||||||
|
isMobile() {
|
||||||
|
return this.$store.state.app.device === 'mobile'
|
||||||
|
},
|
||||||
|
isTablet() {
|
||||||
|
return this.$store.state.app.device === 'tablet'
|
||||||
|
},
|
||||||
|
loading() {
|
||||||
|
return this.$store.state.status.loading
|
||||||
|
},
|
||||||
|
status() {
|
||||||
|
return this.$store.state.status.fetchedStatus
|
||||||
|
},
|
||||||
|
statuses() {
|
||||||
|
return this.$store.state.userProfile.statuses
|
||||||
|
},
|
||||||
|
statusesLoading() {
|
||||||
|
return this.$store.state.userProfile.statusesLoading
|
||||||
|
},
|
||||||
|
user() {
|
||||||
|
return this.$store.state.status.statusAuthor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount: function() {
|
||||||
|
this.$store.dispatch('NeedReboot')
|
||||||
|
this.$store.dispatch('GetNodeInfo')
|
||||||
|
this.$store.dispatch('FetchStatus', this.$route.params.id)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
accountExists(account, key) {
|
||||||
|
return account[key]
|
||||||
|
},
|
||||||
|
closeResetPasswordDialog() {
|
||||||
|
this.resetPasswordDialogOpen = false
|
||||||
|
this.$store.dispatch('RemovePasswordToken')
|
||||||
|
},
|
||||||
|
onTogglePrivate() {
|
||||||
|
this.$store.dispatch('FetchUserStatuses', { userId: this.user.id, godmode: this.showPrivate })
|
||||||
|
},
|
||||||
|
openResetPasswordDialog() {
|
||||||
|
this.resetPasswordDialogOpen = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel='stylesheet/scss' lang='scss'>
|
||||||
|
.avatar-name-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.el-icon-top-right {
|
||||||
|
font-size: 2em;
|
||||||
|
line-height: 36px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.avatar-name-header {
|
||||||
|
display: flex;
|
||||||
|
height: 40px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.no-statuses {
|
||||||
|
margin-left: 28px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
.password-reset-token {
|
||||||
|
margin: 0 0 14px 0;
|
||||||
|
}
|
||||||
|
.password-reset-token-dialog {
|
||||||
|
width: 50%
|
||||||
|
}
|
||||||
|
.reboot-button {
|
||||||
|
padding: 10px;
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-statuses-container-show {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.el-timeline-item {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
.recent-statuses {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
.show-private-statuses {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.reset-password-link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.status-container {
|
||||||
|
margin: 0 15px 0 20px;
|
||||||
|
}
|
||||||
|
.statuses {
|
||||||
|
padding: 0 20px 0 0;
|
||||||
|
}
|
||||||
|
.user-page-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 22px 15px 22px 20px;
|
||||||
|
align-items: center;
|
||||||
|
h1 {
|
||||||
|
display: inline;
|
||||||
|
margin: 0 0 0 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 1824px) {
|
||||||
|
.status-show-container {
|
||||||
|
max-width: 1824px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width:480px) {
|
||||||
|
.avatar-name-container {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.el-timeline-item__wrapper {
|
||||||
|
padding-left: 18px;
|
||||||
|
}
|
||||||
|
.left-header-container {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.password-reset-token-dialog {
|
||||||
|
width: 85%
|
||||||
|
}
|
||||||
|
.recent-statuses {
|
||||||
|
margin: 20px 10px 15px 10px;
|
||||||
|
}
|
||||||
|
.recent-statuses-container-show {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 0 0 10px;
|
||||||
|
.el-timeline-item {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.recent-statuses {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.show-private-statuses {
|
||||||
|
margin: 0 10px 20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.status-card {
|
||||||
|
.el-card__body {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.status-container {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
.statuses {
|
||||||
|
padding-right: 10px;
|
||||||
|
margin-left: 0;
|
||||||
|
.el-timeline-item__wrapper {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.user-page-header {
|
||||||
|
padding: 0;
|
||||||
|
margin: 7px 15px 5px 10px;
|
||||||
|
}
|
||||||
|
.status-page-header-container {
|
||||||
|
width: 100%;
|
||||||
|
.el-dropdown {
|
||||||
|
width: stretch;
|
||||||
|
margin: 0 10px 15px 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width:801px) and (min-width: 481px) {
|
||||||
|
.recent-statuses-container-show {
|
||||||
|
width: 97%;
|
||||||
|
margin: 0 20px;
|
||||||
|
.el-timeline-item {
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
.recent-statuses {
|
||||||
|
margin: 20px 10px 15px 0;
|
||||||
|
}
|
||||||
|
.show-private-statuses {
|
||||||
|
margin: 0 10px 20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.show-private-statuses {
|
||||||
|
margin: 0 10px 20px 0;
|
||||||
|
}
|
||||||
|
.user-page-header {
|
||||||
|
padding: 0;
|
||||||
|
margin: 7px 15px 20px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dropdown :hide-on-click="false" size="small" trigger="click" @click.native.stop>
|
<el-dropdown :hide-on-click="false" size="small" trigger="click" placement="top-start" @click.native.stop>
|
||||||
<div>
|
<div>
|
||||||
<el-button v-if="page === 'users'" type="text" class="el-dropdown-link">
|
<el-button v-if="page === 'users'" type="text" class="el-dropdown-link">
|
||||||
{{ $t('users.moderation') }}
|
{{ $t('users.moderation') }}
|
||||||
<i v-if="isDesktop" class="el-icon-arrow-down el-icon--right"/>
|
<i v-if="isDesktop" class="el-icon-arrow-down el-icon--right"/>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button v-if="page === 'userPage'" class="moderate-user-button">
|
<el-button v-if="page === 'userPage' || page === 'statusPage'" class="moderate-user-button">
|
||||||
<span class="moderate-user-button-container">
|
<span class="moderate-user-button-container">
|
||||||
<span>
|
<span>
|
||||||
<i class="el-icon-edit" />
|
<i class="el-icon-edit" />
|
||||||
|
@ -27,13 +27,13 @@
|
||||||
{{ user.roles.moderator ? $t('users.revokeModerator') : $t('users.grantModerator') }}
|
{{ user.roles.moderator ? $t('users.revokeModerator') : $t('users.grantModerator') }}
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
v-if="showDeactivatedButton(user.id)"
|
v-if="showDeactivatedButton(user.id) && page !== 'statusPage'"
|
||||||
:divided="showAdminAction(user)"
|
:divided="showAdminAction(user)"
|
||||||
@click.native="toggleActivation(user)">
|
@click.native="toggleActivation(user)">
|
||||||
{{ user.deactivated ? $t('users.activateAccount') : $t('users.deactivateAccount') }}
|
{{ user.deactivated ? $t('users.activateAccount') : $t('users.deactivateAccount') }}
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
v-if="showDeactivatedButton(user.id)"
|
v-if="showDeactivatedButton(user.id) && page !== 'statusPage'"
|
||||||
@click.native="handleDeletion(user)">
|
@click.native="handleDeletion(user)">
|
||||||
{{ $t('users.deleteAccount') }}
|
{{ $t('users.deleteAccount') }}
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
@ -115,6 +115,10 @@ export default {
|
||||||
page: {
|
page: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'users'
|
default: 'users'
|
||||||
|
},
|
||||||
|
statusId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -134,7 +138,7 @@ export default {
|
||||||
this.$store.dispatch('DeleteUsers', { users: [user], _userId: user.id })
|
this.$store.dispatch('DeleteUsers', { users: [user], _userId: user.id })
|
||||||
},
|
},
|
||||||
handleEmailConfirmation(user) {
|
handleEmailConfirmation(user) {
|
||||||
this.$store.dispatch('ConfirmUsersEmail', { users: [user], _userId: user.id })
|
this.$store.dispatch('ConfirmUsersEmail', { users: [user], _userId: user.id, _statusId: this.statusId })
|
||||||
},
|
},
|
||||||
requirePasswordReset(user) {
|
requirePasswordReset(user) {
|
||||||
const mailerEnabled = this.$store.state.user.nodeInfo.metadata.mailerEnabled
|
const mailerEnabled = this.$store.state.user.nodeInfo.metadata.mailerEnabled
|
||||||
|
@ -157,13 +161,13 @@ export default {
|
||||||
},
|
},
|
||||||
toggleTag(user, tag) {
|
toggleTag(user, tag) {
|
||||||
user.tags.includes(tag)
|
user.tags.includes(tag)
|
||||||
? this.$store.dispatch('RemoveTag', { users: [user], tag, _userId: user.id })
|
? this.$store.dispatch('RemoveTag', { users: [user], tag, _userId: user.id, _statusId: this.statusId })
|
||||||
: this.$store.dispatch('AddTag', { users: [user], tag, _userId: user.id })
|
: this.$store.dispatch('AddTag', { users: [user], tag, _userId: user.id, _statusId: this.statusId })
|
||||||
},
|
},
|
||||||
toggleUserRight(user, right) {
|
toggleUserRight(user, right) {
|
||||||
user.roles[right]
|
user.roles[right]
|
||||||
? this.$store.dispatch('DeleteRight', { users: [user], right, _userId: user.id })
|
? this.$store.dispatch('DeleteRight', { users: [user], right, _userId: user.id, _statusId: this.statusId })
|
||||||
: this.$store.dispatch('AddRight', { users: [user], right, _userId: user.id })
|
: this.$store.dispatch('AddRight', { users: [user], right, _userId: user.id, _statusId: this.statusId })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
47
src/views/users/components/ResetPasswordDialog.vue
Normal file
47
src/views/users/components/ResetPasswordDialog.vue
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-loading="loading"
|
||||||
|
:visible="dialogOpen"
|
||||||
|
:title="$t('users.passwordResetTokenCreated')"
|
||||||
|
custom-class="password-reset-token-dialog"
|
||||||
|
@close="closeResetPasswordDialog">
|
||||||
|
<div>
|
||||||
|
<p class="password-reset-token">Password reset token was generated: {{ passwordResetToken }}</p>
|
||||||
|
<p>You can also use this link to reset password:
|
||||||
|
<a :href="passwordResetLink" target="_blank" class="reset-password-link">{{ passwordResetLink }}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ResetPasswordDialog',
|
||||||
|
props: {
|
||||||
|
resetPasswordDialogOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dialogOpen() {
|
||||||
|
return this.resetPasswordDialogOpen
|
||||||
|
},
|
||||||
|
loading() {
|
||||||
|
return this.$store.state.users.loading
|
||||||
|
},
|
||||||
|
passwordResetLink() {
|
||||||
|
return this.$store.state.users.passwordResetToken.link
|
||||||
|
},
|
||||||
|
passwordResetToken() {
|
||||||
|
return this.$store.state.users.passwordResetToken.token
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeResetPasswordDialog() {
|
||||||
|
this.$emit('close-reset-token-dialog')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
multiple
|
multiple
|
||||||
class="select-field"
|
class="select-field"
|
||||||
@change="toggleFilters">
|
@change="toggleFilters">
|
||||||
<el-option-group :label="$t('usersFilter.byUserType')">
|
<el-option-group :label="$t('usersFilter.byAccountType')">
|
||||||
<el-option value="local">{{ $t('usersFilter.local') }}</el-option>
|
<el-option value="local">{{ $t('usersFilter.local') }}</el-option>
|
||||||
<el-option value="external">{{ $t('usersFilter.external') }}</el-option>
|
<el-option value="external">{{ $t('usersFilter.external') }}</el-option>
|
||||||
</el-option-group>
|
</el-option-group>
|
||||||
|
|
|
@ -87,19 +87,9 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-dialog
|
<reset-password-dialog
|
||||||
v-loading="loading"
|
:reset-password-dialog-open="resetPasswordDialogOpen"
|
||||||
:visible.sync="resetPasswordDialogOpen"
|
@close-reset-token-dialog="closeResetPasswordDialog"/>
|
||||||
:title="$t('users.passwordResetTokenCreated')"
|
|
||||||
custom-class="password-reset-token-dialog"
|
|
||||||
@close="closeResetPasswordDialog">
|
|
||||||
<div>
|
|
||||||
<p class="password-reset-token">Password reset token was generated: {{ passwordResetToken }}</p>
|
|
||||||
<p>You can also use this link to reset password:
|
|
||||||
<a :href="passwordResetLink" target="_blank" class="reset-password-link">{{ passwordResetLink }}</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
<div v-if="!loading" class="pagination">
|
<div v-if="!loading" class="pagination">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:total="usersCount"
|
:total="usersCount"
|
||||||
|
@ -121,6 +111,7 @@ import MultipleUsersMenu from './components/MultipleUsersMenu'
|
||||||
import NewAccountDialog from './components/NewAccountDialog'
|
import NewAccountDialog from './components/NewAccountDialog'
|
||||||
import ModerationDropdown from './components/ModerationDropdown'
|
import ModerationDropdown from './components/ModerationDropdown'
|
||||||
import RebootButton from '@/components/RebootButton'
|
import RebootButton from '@/components/RebootButton'
|
||||||
|
import ResetPasswordDialog from './components/ResetPasswordDialog'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Users',
|
name: 'Users',
|
||||||
|
@ -129,6 +120,7 @@ export default {
|
||||||
ModerationDropdown,
|
ModerationDropdown,
|
||||||
MultipleUsersMenu,
|
MultipleUsersMenu,
|
||||||
RebootButton,
|
RebootButton,
|
||||||
|
ResetPasswordDialog,
|
||||||
UsersFilter
|
UsersFilter
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -149,12 +141,6 @@ export default {
|
||||||
pageSize() {
|
pageSize() {
|
||||||
return this.$store.state.users.pageSize
|
return this.$store.state.users.pageSize
|
||||||
},
|
},
|
||||||
passwordResetLink() {
|
|
||||||
return this.$store.state.users.passwordResetToken.link
|
|
||||||
},
|
|
||||||
passwordResetToken() {
|
|
||||||
return this.$store.state.users.passwordResetToken.token
|
|
||||||
},
|
|
||||||
currentPage() {
|
currentPage() {
|
||||||
return this.$store.state.users.currentPage
|
return this.$store.state.users.currentPage
|
||||||
},
|
},
|
||||||
|
@ -265,11 +251,6 @@ export default {
|
||||||
.create-account > .el-icon-plus {
|
.create-account > .el-icon-plus {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
.users-header-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.password-reset-token {
|
.password-reset-token {
|
||||||
margin: 0 0 14px 0;
|
margin: 0 0 14px 0;
|
||||||
}
|
}
|
||||||
|
@ -279,6 +260,11 @@ export default {
|
||||||
.reset-password-link {
|
.reset-password-link {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
.users-header-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
.users-container {
|
.users-container {
|
||||||
h1 {
|
h1 {
|
||||||
margin: 10px 0 0 15px;
|
margin: 10px 0 0 15px;
|
||||||
|
|
|
@ -30,19 +30,9 @@
|
||||||
:page="'userPage'"
|
:page="'userPage'"
|
||||||
@open-reset-token-dialog="openResetPasswordDialog"/>
|
@open-reset-token-dialog="openResetPasswordDialog"/>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog
|
<reset-password-dialog
|
||||||
v-loading="loading"
|
:reset-password-dialog-open="resetPasswordDialogOpen"
|
||||||
:visible.sync="resetPasswordDialogOpen"
|
@close-reset-token-dialog="closeResetPasswordDialog"/>
|
||||||
:title="$t('users.passwordResetTokenCreated')"
|
|
||||||
custom-class="password-reset-token-dialog"
|
|
||||||
@close="closeResetPasswordDialog">
|
|
||||||
<div>
|
|
||||||
<p class="password-reset-token">Password reset token was generated: {{ passwordResetToken }}</p>
|
|
||||||
<p>You can also use this link to reset password:
|
|
||||||
<a :href="passwordResetLink" target="_blank" class="reset-password-link">{{ passwordResetLink }}</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
<div class="user-profile-container">
|
<div class="user-profile-container">
|
||||||
<el-card class="user-profile-card">
|
<el-card class="user-profile-card">
|
||||||
<div class="el-table el-table--fit el-table--enable-row-hover el-table--enable-row-transition el-table--medium">
|
<div class="el-table el-table--fit el-table--enable-row-hover el-table--enable-row-transition el-table--medium">
|
||||||
|
@ -77,14 +67,14 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="el-table__row">
|
<tr class="el-table__row">
|
||||||
<td>{{ $t('userProfile.localUppercase') }}</td>
|
<td>{{ $t('userProfile.accountType') }}</td>
|
||||||
<td>
|
<td>
|
||||||
<el-tag v-if="user.local" type="info">{{ $t('userProfile.local') }}</el-tag>
|
<el-tag v-if="user.local" type="info">{{ $t('userProfile.local') }}</el-tag>
|
||||||
<el-tag v-if="!user.local" type="info">{{ $t('userProfile.external') }}</el-tag>
|
<el-tag v-if="!user.local" type="info">{{ $t('userProfile.external') }}</el-tag>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="el-table__row">
|
<tr class="el-table__row">
|
||||||
<td>{{ $t('userProfile.activeUppercase') }}</td>
|
<td>{{ $t('userProfile.status') }}</td>
|
||||||
<td>
|
<td>
|
||||||
<el-tag v-if="!user.deactivated" type="success">{{ $t('userProfile.active') }}</el-tag>
|
<el-tag v-if="!user.deactivated" type="success">{{ $t('userProfile.active') }}</el-tag>
|
||||||
<el-tag v-if="user.deactivated" type="danger">{{ $t('userProfile.deactivated') }}</el-tag>
|
<el-tag v-if="user.deactivated" type="danger">{{ $t('userProfile.deactivated') }}</el-tag>
|
||||||
|
@ -123,10 +113,11 @@ import Status from '@/components/Status'
|
||||||
import ModerationDropdown from './components/ModerationDropdown'
|
import ModerationDropdown from './components/ModerationDropdown'
|
||||||
import SecuritySettingsModal from './components/SecuritySettingsModal'
|
import SecuritySettingsModal from './components/SecuritySettingsModal'
|
||||||
import RebootButton from '@/components/RebootButton'
|
import RebootButton from '@/components/RebootButton'
|
||||||
|
import ResetPasswordDialog from './components/ResetPasswordDialog'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'UsersShow',
|
name: 'UsersShow',
|
||||||
components: { ModerationDropdown, RebootButton, Status, SecuritySettingsModal },
|
components: { ModerationDropdown, RebootButton, ResetPasswordDialog, Status, SecuritySettingsModal },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showPrivate: false,
|
showPrivate: false,
|
||||||
|
@ -147,12 +138,6 @@ export default {
|
||||||
loading() {
|
loading() {
|
||||||
return this.$store.state.users.loading
|
return this.$store.state.users.loading
|
||||||
},
|
},
|
||||||
passwordResetLink() {
|
|
||||||
return this.$store.state.users.passwordResetToken.link
|
|
||||||
},
|
|
||||||
passwordResetToken() {
|
|
||||||
return this.$store.state.users.passwordResetToken.token
|
|
||||||
},
|
|
||||||
statuses() {
|
statuses() {
|
||||||
return this.$store.state.userProfile.statuses
|
return this.$store.state.userProfile.statuses
|
||||||
},
|
},
|
||||||
|
@ -179,6 +164,17 @@ export default {
|
||||||
this.resetPasswordDialogOpen = false
|
this.resetPasswordDialogOpen = false
|
||||||
this.$store.dispatch('RemovePasswordToken')
|
this.$store.dispatch('RemovePasswordToken')
|
||||||
},
|
},
|
||||||
|
humanizeTag(tag) {
|
||||||
|
const mapTags = {
|
||||||
|
'force_nsfw': 'Force NSFW',
|
||||||
|
'strip_media': 'Strip Media',
|
||||||
|
'force_unlisted': 'Force Unlisted',
|
||||||
|
'sandbox': 'Sandbox',
|
||||||
|
'disable_remote_subscription': 'Disable remote subscription',
|
||||||
|
'disable_any_subscription': 'Disable any subscription'
|
||||||
|
}
|
||||||
|
return mapTags[tag]
|
||||||
|
},
|
||||||
onTogglePrivate() {
|
onTogglePrivate() {
|
||||||
this.$store.dispatch('FetchUserProfile', { userId: this.$route.params.id, godmode: this.showPrivate })
|
this.$store.dispatch('FetchUserProfile', { userId: this.$route.params.id, godmode: this.showPrivate })
|
||||||
},
|
},
|
||||||
|
@ -192,7 +188,7 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style rel='stylesheet/scss' lang='scss' scoped>
|
<style rel='stylesheet/scss' lang='scss'>
|
||||||
header {
|
header {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -241,6 +237,12 @@ table {
|
||||||
margin-left: 28px;
|
margin-left: 28px;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
}
|
}
|
||||||
|
.password-reset-token {
|
||||||
|
margin: 0 0 14px 0;
|
||||||
|
}
|
||||||
|
.password-reset-token-dialog {
|
||||||
|
width: 50%
|
||||||
|
}
|
||||||
.poll ul {
|
.poll ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -258,6 +260,9 @@ table {
|
||||||
.recent-statuses-header {
|
.recent-statuses-header {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
.reset-password-link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
.security-setting-button {
|
.security-setting-button {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -307,16 +312,29 @@ table {
|
||||||
.avatar-name-container {
|
.avatar-name-container {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
.el-timeline-item__wrapper {
|
||||||
|
padding-left: 18px;
|
||||||
|
}
|
||||||
|
.password-reset-token-dialog {
|
||||||
|
width: 85%
|
||||||
|
}
|
||||||
.recent-statuses {
|
.recent-statuses {
|
||||||
margin: 20px 10px 15px 10px;
|
margin: 20px 10px 15px 10px;
|
||||||
}
|
}
|
||||||
.recent-statuses-container {
|
.recent-statuses-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 10px;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.show-private-statuses {
|
.show-private-statuses {
|
||||||
margin: 0 10px 20px 10px;
|
margin: 0 10px 20px 10px;
|
||||||
}
|
}
|
||||||
|
.status-container {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
.statuses {
|
||||||
|
padding-right: 10px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
.user-page-header {
|
.user-page-header {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 7px 15px 15px 10px;
|
margin: 7px 15px 15px 10px;
|
||||||
|
|
91
test/views/statuses/show.test.js
Normal file
91
test/views/statuses/show.test.js
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import { mount, createLocalVue, config } from '@vue/test-utils'
|
||||||
|
import flushPromises from 'flush-promises'
|
||||||
|
import Element from 'element-ui'
|
||||||
|
import StatusShow from '@/views/statuses/show'
|
||||||
|
import storeConfig from './statusShowStore.conf'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
|
||||||
|
config.mocks["$t"] = () => {}
|
||||||
|
|
||||||
|
const localVue = createLocalVue()
|
||||||
|
localVue.use(Vuex)
|
||||||
|
localVue.use(Element)
|
||||||
|
|
||||||
|
const $route = {
|
||||||
|
params: {
|
||||||
|
id: '9vJOO3iFPyjNaEhJ5s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.mock('@/api/app')
|
||||||
|
jest.mock('@/api/status')
|
||||||
|
jest.mock('@/api/peers')
|
||||||
|
jest.mock('@/api/nodeInfo')
|
||||||
|
jest.mock('@/api/users')
|
||||||
|
|
||||||
|
describe('Status show page', () => {
|
||||||
|
let store
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
store = new Vuex.Store(cloneDeep(storeConfig))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`fetches single status and user's statuses`, async (done) => {
|
||||||
|
const wrapper = mount(StatusShow, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
sync: false,
|
||||||
|
stubs: ['router-link'],
|
||||||
|
mocks: {
|
||||||
|
$route
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(wrapper.find('.status-container').isVisible()).toBe(true)
|
||||||
|
expect(store.state.status.fetchedStatus.id).toBe('9vJOO3iFPyjNaEhJ5s')
|
||||||
|
expect(store.state.status.fetchedStatus.account.display_name).toBe('dolin')
|
||||||
|
expect(store.state.userProfile.statuses.length).toEqual(3)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`renders links and user's moderation menu`, async (done) => {
|
||||||
|
const wrapper = mount(StatusShow, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
sync: false,
|
||||||
|
stubs: ['router-link'],
|
||||||
|
mocks: {
|
||||||
|
$route
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(wrapper.find('router-link-stub h1').text()).toBe('dolin')
|
||||||
|
expect(wrapper.find('button.moderate-user-button').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('.el-dropdown-menu').exists()).toBe(true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`renders status card`, async (done) => {
|
||||||
|
const wrapper = mount(StatusShow, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
sync: false,
|
||||||
|
stubs: ['router-link'],
|
||||||
|
mocks: {
|
||||||
|
$route
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(wrapper.find('.status-card').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('router-link-stub h3').text()).toBe('dolin')
|
||||||
|
expect(wrapper.find('span.el-tag').text()).not.toBe('Sensitive')
|
||||||
|
expect(wrapper.find('span.el-tag').text()).toBe('Public')
|
||||||
|
expect(wrapper.find('button.status-actions-button').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('.status-body .status-content').text()).toBe('pizza makes everything better')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
21
test/views/statuses/statusShowStore.conf.js
Normal file
21
test/views/statuses/statusShowStore.conf.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import app from '@/store/modules/app'
|
||||||
|
import peers from '@/store/modules/peers'
|
||||||
|
import user from '@/store/modules/user'
|
||||||
|
import userProfile from '@/store/modules/userProfile'
|
||||||
|
import users from '@/store/modules/users'
|
||||||
|
import settings from '@/store/modules/settings'
|
||||||
|
import status from '@/store/modules/status'
|
||||||
|
import getters from '@/store/getters'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
modules: {
|
||||||
|
app,
|
||||||
|
peers,
|
||||||
|
settings,
|
||||||
|
status,
|
||||||
|
user,
|
||||||
|
userProfile,
|
||||||
|
users
|
||||||
|
},
|
||||||
|
getters
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ const $route = {
|
||||||
jest.mock('@/api/nodeInfo')
|
jest.mock('@/api/nodeInfo')
|
||||||
jest.mock('@/api/users')
|
jest.mock('@/api/users')
|
||||||
|
|
||||||
describe('Search and filter users', () => {
|
describe('User profile', () => {
|
||||||
let store
|
let store
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
Loading…
Reference in a new issue