Merge branch 'feature/show-reboot-button' into 'develop'

Show reboot button on every page

Closes #98

See merge request pleroma/admin-fe!122
This commit is contained in:
Angelina Filippova 2020-04-17 22:27:00 +00:00
commit f1e1832c7e
51 changed files with 2032 additions and 964 deletions

View file

@ -10,6 +10,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Link settings that enable registrations and invites
### Changed
- Put Instance Reboot button on all pages of admin-fe
- Make Instance Reboot button's positon fixed on Settings page
- Update jest and babel-jest
### Fixed
- Disable Invites tab when invites are disabled on BE

View file

@ -81,7 +81,7 @@
"autoprefixer": "8.5.0",
"babel-eslint": "8.2.6",
"babel-helper-vue-jsx-merge-props": "2.0.3",
"babel-jest": "^24.1.0",
"babel-jest": "^25.3.0",
"babel-loader": "^8.0.5",
"babel-plugin-dynamic-import-node-babel-7": "^2.0.7",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
@ -101,7 +101,7 @@
"hash-sum": "1.0.2",
"html-webpack-plugin": "^3.2.0",
"husky": "0.14.3",
"jest": "^24.1.0",
"jest": "^25.3.0",
"jest-transform-stub": "^2.0.0",
"lint-staged": "7.2.2",
"mini-css-extract-plugin": "0.4.1",

7
src/api/__mocks__/app.js Normal file
View file

@ -0,0 +1,7 @@
export async function needReboot(authHost, token) {
return Promise.resolve({ data: false })
}
export async function restartApp(authHost, token) {
return Promise.resolve()
}

View file

@ -28,6 +28,10 @@ export async function fetchUser(id, authHost, token) {
return Promise.resolve({ data: userProfile })
}
export async function fetchUserCredentials(nickname, authHost, token) {
return Promise.resolve({ data: {}})
}
export async function fetchUsers(filters, authHost, token, page = 1) {
const filteredUsers = filterUsers(filters)
return Promise.resolve({ data: {

23
src/api/app.js Normal file
View file

@ -0,0 +1,23 @@
import request from '@/utils/request'
import { getToken } from '@/utils/auth'
import { baseName } from './utils'
export async function needReboot(authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/need_reboot`,
method: 'get',
headers: authHeaders(token)
})
}
export async function restartApp(authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/restart`,
method: 'get',
headers: authHeaders(token)
})
}
const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}

View file

@ -40,13 +40,4 @@ export async function removeSettings(configs, authHost, token) {
})
}
export async function restartApp(authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/restart`,
method: 'get',
headers: authHeaders(token)
})
}
const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}

View file

@ -0,0 +1,36 @@
<template>
<el-tooltip v-if="needReboot" :content="$t('settings.restartApp')" placement="bottom-end">
<el-button type="warning" class="reboot-button" @click="restartApp">
<span>
<i class="el-icon-refresh"/>
{{ $t('settings.instanceReboot') }}
</span>
</el-button>
</el-tooltip>
</template>
<script>
import i18n from '@/lang'
export default {
name: 'RebootButton',
computed: {
needReboot() {
return this.$store.state.app.needReboot
}
},
methods: {
async restartApp() {
try {
await this.$store.dispatch('RestartApplication')
} catch (e) {
return
}
this.$message({
type: 'success',
message: i18n.t('settings.restartSuccess')
})
}
}
}
</script>

View file

@ -383,7 +383,7 @@ export default {
emoji: 'Emoji',
markup: 'Markup settings',
corsPlug: 'CORS plug config',
instanceReboot: 'Instance Reboot',
instanceReboot: 'Reboot Instance',
restartApp: 'You must restart the instance to apply settings',
restartSuccess: 'Instance rebooted successfully!'
},

View file

@ -1,4 +1,5 @@
import Cookies from 'js-cookie'
import { needReboot, restartApp } from '@/api/app'
const app = {
state: {
@ -8,6 +9,7 @@ const app = {
},
device: 'desktop',
language: Cookies.get('language') || 'en',
needReboot: false,
size: Cookies.get('size') || 'medium',
invitesEnabled: false
},
@ -36,20 +38,25 @@ const app = {
state.language = language
Cookies.set('language', language)
},
TOGGLE_REBOOT: (state, needReboot) => {
state.needReboot = needReboot
},
SET_SIZE: (state, size) => {
state.size = size
Cookies.set('size', size)
}
},
actions: {
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
},
closeSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation)
},
toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
async NeedReboot({ commit, getters }) {
const response = await needReboot(getters.authHost, getters.token)
commit('TOGGLE_REBOOT', response.data['need_reboot'])
},
async RestartApplication({ commit, getters }) {
await restartApp(getters.authHost, getters.token)
commit('TOGGLE_REBOOT', false)
},
SetInvitesEnabled({ commit }, invitesEnabled) {
commit('SET_INVITES_ENABLED', invitesEnabled)
@ -59,6 +66,12 @@ const app = {
},
setSize({ commit }, size) {
commit('SET_SIZE', size)
},
toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
},
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
}
}
}

View file

@ -1,4 +1,4 @@
import { fetchDescription, fetchSettings, removeSettings, restartApp, updateSettings } from '@/api/settings'
import { fetchDescription, fetchSettings, removeSettings, updateSettings } from '@/api/settings'
import { checkPartialUpdate, formSearchObject, parseNonTuples, parseTuples, valueHasTuples, wrapUpdatedSettings } from './normalizers'
import _ from 'lodash'
@ -9,7 +9,6 @@ const settings = {
db: {},
description: [],
loading: true,
needReboot: false,
searchData: {},
settings: {},
updatedSettings: {}
@ -55,9 +54,6 @@ const settings = {
state.settings = newSettings
state.db = newDbSettings
},
TOGGLE_REBOOT: (state, needReboot) => {
state.needReboot = needReboot || false
},
TOGGLE_TABS: (state, status) => {
state.configDisabled = status
},
@ -84,7 +80,6 @@ const settings = {
const searchObject = formSearchObject(description.data)
commit('SET_SEARCH', searchObject)
commit('SET_SETTINGS', response.data.configs)
commit('TOGGLE_REBOOT', response.data.need_reboot)
} catch (_e) {
commit('TOGGLE_TABS', true)
commit('SET_ACTIVE_TAB', 'relays')
@ -102,10 +97,6 @@ const settings = {
commit('TOGGLE_REBOOT', response.data.need_reboot)
commit('REMOVE_SETTING_FROM_UPDATED', { group, key, subkeys: subkeys || [] })
},
async RestartApplication({ commit, getters }) {
await restartApp(getters.authHost, getters.token)
commit('TOGGLE_REBOOT', false)
},
SetActiveTab({ commit }, tab) {
commit('SET_ACTIVE_TAB', tab)
},

View file

@ -18,7 +18,7 @@
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
z-index: 5000;
overflow: hidden;
//reset element-ui css

View file

@ -1,6 +1,10 @@
<template>
<div class="emoji-packs">
<h1 class="emoji-packs-header">{{ $t('emoji.emojiPacks') }}</h1>
<div class="emoji-packs-header">
<h1>{{ $t('emoji.emojiPacks') }}</h1>
<reboot-button/>
</div>
<div class="emoji-header-container">
<div class="emoji-packs-header-button-container">
<el-button type="primary" class="reload-emoji-button" @click="reloadEmoji">{{ $t('emoji.reloadEmoji') }}</el-button>
<el-tooltip :content="$t('emoji.importEmojiTooltip')" effects="dark" placement="bottom" class="import-pack-button">
@ -9,6 +13,7 @@
</el-button>
</el-tooltip>
</div>
</div>
<el-divider class="divider"/>
<el-form :label-width="labelWidth" class="emoji-packs-form">
<el-form-item :label="$t('emoji.localPacks')">
@ -58,9 +63,10 @@
import LocalEmojiPack from './components/LocalEmojiPack'
import RemoteEmojiPack from './components/RemoteEmojiPack'
import i18n from '@/lang'
import RebootButton from '@/components/RebootButton'
export default {
components: { LocalEmojiPack, RemoteEmojiPack },
components: { LocalEmojiPack, RebootButton, RemoteEmojiPack },
data() {
return {
remoteInstanceAddress: '',
@ -94,6 +100,8 @@ export default {
}
},
mounted() {
this.$store.dispatch('GetNodeInfo')
this.$store.dispatch('NeedReboot')
this.refreshLocalPacks()
},
methods: {
@ -149,9 +157,14 @@ export default {
</script>
<style rel='stylesheet/scss' lang='scss'>
.emoji-header-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 15px 22px 15px;
}
.emoji-packs-header-button-container {
display: flex;
margin: 0 0 22px 15px;
}
.create-pack {
display: flex;
@ -164,17 +177,28 @@ export default {
margin: 0 30px;
}
.emoji-packs-header {
margin: 10px 0 20px 15px;
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 15px 15px 15px;
}
.import-pack-button {
margin-left: 10px;
}
h1 {
margin: 0;
}
.line {
width: 100%;
height: 0;
border: 1px solid #eee;
margin-bottom: 22px;
}
}
.reboot-button {
padding: 10px;
margin: 0;
width: 145px;
}
@media only screen and (min-width: 1824px) {
.emoji-packs {
@ -200,6 +224,10 @@ export default {
.el-message-box {
width: 80%;
}
.emoji-header-container {
flex-direction: column;
align-items: flex-start;
}
.emoji-packs-form {
margin: 0 7px;
label {

View file

@ -1,6 +1,9 @@
<template>
<div class="invites-container">
<div class="invites-header-container">
<h1>{{ $t('invites.inviteTokens') }}</h1>
<reboot-button/>
</div>
<div class="actions-container">
<el-button class="create-invite-token" @click="createTokenDialogVisible = true">
<span>
@ -140,7 +143,10 @@
</template>
<script>
import RebootButton from '@/components/RebootButton'
export default {
components: { RebootButton },
data() {
return {
rules: {
@ -178,6 +184,8 @@ export default {
}
},
mounted() {
this.$store.dispatch('GetNodeInfo')
this.$store.dispatch('NeedReboot')
this.$store.dispatch('FetchInviteTokens')
},
methods: {
@ -232,7 +240,7 @@ export default {
height: 36px;
justify-content: space-between;
align-items: center;
margin: 20px 15px 15px 15px;
margin: 15px 15px 15px 15px;
}
.create-invite-token {
text-align: left;
@ -246,7 +254,7 @@ export default {
padding: 5px 20px 0 20px
}
h1 {
margin: 10px 0 0 15px;
margin: 0;
}
.icon {
margin-right: 5px;
@ -263,12 +271,23 @@ export default {
.invite-via-email-dialog {
width: 50%
}
.invites-header-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 15px;
}
.info {
color: #666666;
font-size: 13px;
line-height: 22px;
margin: 0 0 10px 0;
}
.reboot-button {
padding: 10px;
margin: 0;
width: 145px;
}
}
@media only screen and (max-width:480px) {
@ -296,7 +315,7 @@ export default {
padding: 5px 15px 0 15px
}
h1 {
margin: 7px 10px 15px 10px;
margin: 0;
}
.invite-token-table {
width: 100%;
@ -311,6 +330,9 @@ export default {
.invite-via-email-dialog {
width: 85%
}
.invites-header-container {
margin: 0 10px;
}
.info {
margin: 0 0 10px 5px;
}

View file

@ -82,7 +82,7 @@ export default {
.right-menu-item {
display: inline-block;
padding: 0 8px;
padding: 0 15px;
height: 100%;
font-size: 18px;
color: #5a5e66;

View file

@ -1,6 +1,9 @@
<template>
<div v-if="!loading" class="moderation-log-container">
<div class="moderation-log-header-container">
<h1>{{ $t('moderationLog.moderationLog') }}</h1>
<reboot-button/>
</div>
<div class="moderation-log-nav-container">
<el-select
v-model="user"
@ -60,8 +63,10 @@
import moment from 'moment'
import _ from 'lodash'
import debounce from 'lodash.debounce'
import RebootButton from '@/components/RebootButton'
export default {
components: { RebootButton },
data() {
return {
dateRange: '',
@ -103,6 +108,8 @@ export default {
}, 500)
},
mounted() {
this.$store.dispatch('GetNodeInfo')
this.$store.dispatch('NeedReboot')
this.$store.dispatch('FetchModerationLog')
this.$store.dispatch('FetchAdmins')
},
@ -130,7 +137,7 @@ export default {
margin: 0 15px;
}
h1 {
margin: 10px 0 20px 0;
margin: 0;
}
.el-timeline {
margin: 25px 45px 0 0;
@ -139,6 +146,12 @@ h1 {
.moderation-log-date-panel {
width: 350px;
}
.moderation-log-header-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 0 15px 0;
}
.moderation-log-nav-container {
display: flex;
justify-content: space-between;
@ -150,6 +163,11 @@ h1 {
margin: 0 0 20px;
width: 350px;
}
.reboot-button {
padding: 10px;
margin: 0;
width: 145px;
}
.search-container {
text-align: right;
}
@ -158,6 +176,9 @@ h1 {
}
@media only screen and (max-width:480px) {
h1 {
font-size: 24px;
}
.moderation-log-date-panel {
width: 100%;
}

View file

@ -8,7 +8,7 @@
placement="top"
class="timeline-item-container">
<el-card class="report">
<div class="header-container">
<div class="report-header-container">
<div class="title-container">
<h3 class="report-title">{{ $t('reports.reportOn') }} {{ report.account.display_name }}</h3>
<h5 class="id">{{ $t('reports.id') }}: {{ report.id }}</h5>
@ -212,7 +212,7 @@ export default {
height: 17px;
}
.report {
.header-container {
.report-header-container {
display: flex;
justify-content: space-between;
align-items: baseline;
@ -285,7 +285,7 @@ export default {
@media only screen and (max-width:480px) {
.report {
.header-container {
.report-header-container {
display: flex;
flex-direction: column;
justify-content: flex-start;

View file

@ -1,9 +1,12 @@
<template>
<div class="reports-container">
<div class="reports-header-container">
<h1>
{{ $t('reports.reports') }}
<span class="report-count">({{ normalizedReportsCount }})</span>
</h1>
<reboot-button/>
</div>
<div class="reports-filter-container">
<reports-filter/>
</div>
@ -20,9 +23,10 @@
import numeral from 'numeral'
import Report from './components/Report'
import ReportsFilter from './components/ReportsFilter'
import RebootButton from '@/components/RebootButton'
export default {
components: { Report, ReportsFilter },
components: { RebootButton, Report, ReportsFilter },
computed: {
loading() {
return this.$store.state.reports.loading
@ -35,6 +39,8 @@ export default {
}
},
mounted() {
this.$store.dispatch('GetNodeInfo')
this.$store.dispatch('NeedReboot')
this.$store.dispatch('FetchReports', 1)
}
}
@ -42,15 +48,26 @@ export default {
<style rel='stylesheet/scss' lang='scss' scoped>
.reports-container {
.reboot-button {
padding: 10px;
margin: 0;
width: 145px;
}
.reports-filter-container {
display: flex;
flex-direction: column;
align-items: flex-start;
margin: 22px 15px 22px 15px;
align-items: center;
justify-content: space-between;
margin: 15px 45px 22px 15px;
padding-bottom: 0
}
.reports-header-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 15px;
}
h1 {
margin: 10px 0 0 15px;
margin: 0;
}
.no-reports-message {
color: gray;
@ -67,6 +84,13 @@ export default {
h1 {
margin: 7px 10px 15px 10px;
}
.reboot-button {
margin: 0 0 5px 10px;
width: 145px;
}
.report-count {
font-size: 22px;
}
.reports-filter-container {
margin: 0 10px;
}

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="activitypubData" :model="activitypubData" :label-width="labelWidth" data-search=":activitypub">
<setting :setting-group="activitypub" :data="activitypubData"/>
</el-form>
@ -35,6 +35,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="pleromaAuthenticatorData" :model="pleromaAuthenticatorData" :label-width="labelWidth">
<setting :setting-group="pleromaAuthenticator" :data="pleromaAuthenticatorData"/>
</el-form>
@ -43,6 +43,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="autoLinker" :model="autoLinkerData" :label-width="labelWidth">
<setting :setting-group="autoLinker" :data="autoLinkerData"/>
</el-form>
@ -31,6 +31,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="captchaData" :model="captchaData" :label-width="labelWidth">
<setting :setting-group="captcha" :data="captchaData"/>
</el-form>
@ -35,6 +35,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="esshdData" :model="esshdData" :label-width="labelWidth">
<setting :setting-group="esshd" :data="esshdData"/>
</el-form>
@ -31,6 +31,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="frontendData" :model="frontendData" :label-width="labelWidth">
<setting :setting-group="frontend" :data="frontendData"/>
</el-form>
@ -77,6 +77,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form v-if="!loading" ref="gopher" :model="gopherData" :label-width="labelWidth">
<setting :setting-group="gopher" :data="gopherData"/>
</el-form>
@ -31,6 +31,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="httpData" :model="httpData" :label-width="labelWidth">
<setting :setting-group="http" :data="httpData"/>
</el-form>
@ -67,6 +67,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="obanQueuesData" :model="obanQueuesData" :label-width="labelWidth">
<setting :setting-group="obanQueues" :data="obanQueuesData"/>
</el-form>
@ -37,6 +37,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="loggerData" :model="loggerData" :label-width="labelWidth">
<setting :setting-group="logger" :data="loggerData"/>
</el-form>
@ -49,6 +49,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="mrfSimple" :model="mrfSimpleData" :label-width="labelWidth">
<setting :setting-group="mrfSimple" :data="mrfSimpleData"/>
</el-form>
@ -59,6 +59,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="mailer" :model="mailerData" :label-width="labelWidth">
<setting :setting-group="mailer" :data="mailerData"/>
</el-form>
@ -47,6 +47,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form v-if="!loading" ref="mediaProxy" :model="mediaProxyData" :label-width="labelWidth">
<setting :setting-group="mediaProxy" :data="mediaProxyData"/>
</el-form>
@ -25,6 +25,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="metadata" :model="metadataData" :label-width="labelWidth">
<setting :setting-group="metadata" :data="metadataData"/>
</el-form>
@ -29,6 +29,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="mimeTypes" :model="mimeTypesData" :label-width="labelWidth">
<setting :setting-group="mimeTypes" :data="mimeTypesData"/>
</el-form>
@ -28,6 +28,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form v-if="!loading" ref="rateLimiters" :model="rateLimitersData" :label-width="labelWidth">
<setting :setting-group="rateLimiters" :data="rateLimitersData"/>
</el-form>
@ -31,6 +31,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form ref="uploadData" :model="uploadData" :label-width="labelWidth">
<setting :setting-group="upload" :data="uploadData"/>
</el-form>
@ -43,6 +43,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!loading" class="form-container">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form v-if="!loading" ref="vapidDetailsData" :model="vapidDetailsData" :label-width="labelWidth">
<setting :setting-group="vapidDetails" :data="vapidDetailsData"/>
</el-form>
@ -25,6 +25,9 @@ export default {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'sidebar-opened' : 'sidebar-closed'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},

View file

@ -1,17 +1,12 @@
<template>
<div class="settings-container">
<div :class="rebootIsSidebarOpen" class="settings-container">
<div class="reboot-button-container">
<reboot-button/>
</div>
<div v-if="isDesktop">
<div :class="isSidebarOpen" class="settings-header-container">
<h1 class="settings-header">{{ $t('settings.settings') }}</h1>
<div>
<el-tooltip v-if="needReboot" :content="$t('settings.restartApp')" placement="bottom-end">
<el-button type="warning" class="settings-reboot-button" @click="restartApp">
<span>
<i class="el-icon-refresh"/>
{{ $t('settings.instanceReboot') }}
</span>
</el-button>
</el-tooltip>
<div class="docs-search-container">
<el-link
:underline="false"
href="https://docs-develop.pleroma.social/backend/administration/CLI_tasks/config/"
@ -49,12 +44,6 @@
<div v-if="isMobile || isTablet">
<div :class="isSidebarOpen" class="settings-header-container">
<h1 class="settings-header">{{ $t('settings.settings') }}</h1>
<el-button v-if="needReboot" class="settings-reboot-button" @click="restartApp">
<span>
<i class="el-icon-refresh"/>
{{ $t('settings.instanceReboot') }}
</span>
</el-button>
</div>
<div class="nav-container">
<el-select v-model="activeTab" class="settings-menu" placeholder="Select">
@ -127,6 +116,7 @@ import {
Upload,
WebPush
} from './components'
import RebootButton from '@/components/RebootButton'
export default {
components: {
@ -148,6 +138,7 @@ export default {
Other,
RateLimiters,
Relays,
RebootButton,
Upload,
WebPush
},
@ -202,8 +193,8 @@ export default {
isTablet() {
return this.$store.state.app.device === 'tablet'
},
needReboot() {
return this.$store.state.settings.needReboot
rebootIsSidebarOpen() {
return this.$store.state.app.sidebar.opened ? 'reboot-sidebar-opened' : 'reboot-sidebar-closed'
},
searchData() {
return this.$store.state.settings.searchData
@ -213,20 +204,11 @@ export default {
}
},
mounted: function() {
this.$store.dispatch('GetNodeInfo')
this.$store.dispatch('NeedReboot')
this.$store.dispatch('FetchSettings')
},
methods: {
async restartApp() {
try {
await this.$store.dispatch('RestartApplication')
} catch (e) {
return
}
this.$message({
type: 'success',
message: i18n.t('settings.restartSuccess')
})
},
async handleSearchSelect(selectedValue) {
const tab = Object.keys(this.tabs).find(tab => {
return this.tabs[tab].settings.includes(selectedValue.group === ':pleroma' ? selectedValue.key : selectedValue.group)
@ -250,7 +232,7 @@ export default {
}
</script>
<style rel='stylesheet/scss' lang='scss'>
<style rel='stylesheet/scss' lang='scss' scoped>
@import './styles/main';
@include settings
</style>

View file

@ -40,6 +40,10 @@
.divider.thick-line {
height: 2px;
}
.docs-search-container {
float: right;
margin-right: 30px;
}
.editable-keyword-container {
width: 100%;
}
@ -230,6 +234,20 @@
width: 100%;
margin-right: 10px;
}
.reboot-button {
width: 145px;
text-align: left;
padding: 10px;
float: right;
margin: 0 30px 0 0;
}
.reboot-button-container {
width: 100%;
position: fixed;
top: 60px;
right: 0;
z-index: 2000;
}
.relays-container {
margin: 0 15px;
}
@ -262,7 +280,7 @@
padding: 10px;
}
.settings-header {
margin: 0;
margin: 10px 15px 15px 15px;
}
.header-sidebar-opened {
max-width: 1585px;
@ -271,17 +289,7 @@
max-width: 1728px;
}
.settings-header-container {
display: flex;
height: 36px;
justify-content: space-between;
align-items: center;
margin: 22px 30px 15px 15px;
}
.settings-reboot-button {
width: 145px;
text-align: left;
padding: 10px;
margin-right: 5px;
height: 87px;
}
.settings-search-input {
width: 350px;
@ -336,6 +344,25 @@
}
@media only screen and (min-width: 1824px) {
.header-sidebar-closed {
max-width: 1772px;
}
.header-sidebar-opened {
max-width: 1630px;
}
.reboot-button-container {
width: 100%;
max-width: inherit;
margin-left: auto;
margin-right: auto;
right: auto;
}
.reboot-sidebar-opened {
max-width: 1630px;
}
.reboot-sidebar-closed {
max-width: 1772px;
}
.sidebar-closed {
max-width: 1586px;
}
@ -392,6 +419,9 @@
display: flex;
justify-content: space-between;
}
h1 {
font-size: 24px;
}
.input {
flex: 1 1 auto;
}
@ -455,6 +485,12 @@
.rate-limit-label {
float: left;
}
.reboot-button {
margin: 0 15px 0 0;
}
.reboot-button-container {
top: 57px;
}
.scale-input {
width: 45%;
}
@ -465,11 +501,11 @@
.settings-header {
width: fit-content;
display: inline-block;
margin: 0;
}
.settings-header-container {
margin: 10px 15px 15px 15px;
}
.docs-search-container {
float: right;
}
.settings-search-input {
width: 100%;
margin-left: 0;
@ -479,6 +515,7 @@
}
.settings-menu {
width: 163px;
margin-right: 5px;
}
.socks5-checkbox-container {
width: 100%;
@ -548,6 +585,9 @@
margin-left: 4px;
margin-right: 5px
}
.settings-header-container {
height: 45px;
}
.value-input {
width: 60%;
margin-left: 5px;
@ -598,6 +638,9 @@
.settings-delete-button {
float: right;
}
.settings-header-container {
height: 36px;
}
.settings-search-input {
width: 250px;
margin: 0 0 15px 15px;

View file

@ -1,14 +1,19 @@
<template>
<div v-if="!loadingPeers" class="statuses-container">
<div class="statuses-header">
<h1>
{{ $t('statuses.statuses') }}
</h1>
<reboot-button/>
</div>
<div class="statuses-header-container">
<el-button-group>
<el-button plain>{{ $t('statuses.direct') }}: {{ statusVisibility.direct }}</el-button>
<el-button plain>{{ $t('statuses.private') }}: {{ statusVisibility.private }}</el-button>
<el-button plain>{{ $t('statuses.public') }}: {{ statusVisibility.public }}</el-button>
<el-button plain>{{ $t('statuses.unlisted') }}: {{ statusVisibility.unlisted }}</el-button>
</el-button-group>
</div>
<div class="filter-container">
<el-select
v-model="selectedInstance"
@ -54,11 +59,13 @@
<script>
import MultipleUsersMenu from '@/views/users/components/MultipleUsersMenu'
import Status from '@/components/Status'
import RebootButton from '@/components/RebootButton'
export default {
name: 'Statuses',
components: {
MultipleUsersMenu,
RebootButton,
Status
},
data() {
@ -82,6 +89,12 @@ export default {
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},
loadingPeers() {
return this.$store.state.peers.loading
},
@ -123,6 +136,8 @@ export default {
}
},
mounted() {
this.$store.dispatch('GetNodeInfo')
this.$store.dispatch('NeedReboot')
this.$store.dispatch('FetchPeers')
this.$store.dispatch('FetchStatusesCount')
},
@ -169,8 +184,23 @@ export default {
align-items: center;
margin: 22px 0 15px 0;
}
.reboot-button {
padding: 10px;
margin: 0;
width: 145px;
}
.select-instance {
width: 350px;
width: 396px;
}
.statuses-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.statuses-header-container {
display: flex;
align-items: center;
justify-content: space-between;
}
.statuses-pagination {
padding: 15px 0;
@ -194,5 +224,15 @@ export default {
.select-instance {
width: 100%;
}
.statuses-header-container {
flex-direction: column;
align-items: flex-start;
.el-button {
padding: 10px 6.5px;
}
.reboot-button {
margin: 10px 0 0 0;
}
}
}
</style>

View file

@ -179,4 +179,9 @@ export default {
display: flex;
justify-content: space-between;
}
@media only screen and (max-width:480px) {
.moderate-user-button {
width: 100%
}
}
</style>

View file

@ -68,10 +68,4 @@ export default {
margin-bottom: 5px;
}
}
@media only screen and (max-width:801px) and (min-width: 481px) {
.select-field {
width: 50%;
}
}
</style>

View file

@ -1,9 +1,12 @@
<template>
<div class="users-container">
<div class="users-header-container">
<h1>
{{ $t('users.users') }}
<span class="user-count">({{ normalizedUsersCount }})</span>
</h1>
<reboot-button/>
</div>
<div class="filter-container">
<users-filter/>
<el-input
@ -111,6 +114,7 @@ import UsersFilter from './components/UsersFilter'
import MultipleUsersMenu from './components/MultipleUsersMenu'
import NewAccountDialog from './components/NewAccountDialog'
import ModerationDropdown from './components/ModerationDropdown'
import RebootButton from '@/components/RebootButton'
export default {
name: 'Users',
@ -118,6 +122,7 @@ export default {
NewAccountDialog,
ModerationDropdown,
MultipleUsersMenu,
RebootButton,
UsersFilter
},
data() {
@ -169,6 +174,7 @@ export default {
}, 500)
},
mounted: function() {
this.$store.dispatch('NeedReboot')
this.$store.dispatch('FetchUsers', { page: 1 })
},
methods: {
@ -222,6 +228,9 @@ export default {
justify-content: space-between;
align-items: center;
margin: 0 15px 10px 15px;
.el-dropdown {
margin-left: 10px;
}
}
.active-tag {
color: #409EFF;
@ -239,6 +248,11 @@ export default {
.create-account > .el-icon-plus {
margin-right: 5px;
}
.users-header-container {
display: flex;
align-items: center;
justify-content: space-between;
}
.password-reset-token {
margin: 0 0 14px 0;
}
@ -251,23 +265,28 @@ export default {
.users-container {
h1 {
margin: 10px 0 0 15px;
height: 40px;
}
.pagination {
margin: 25px 0;
text-align: center;
}
.reboot-button {
margin: 0 15px 0 0;
padding: 10px;
width: 145px;
}
.search {
width: 350px;
float: right;
margin-left: 10px;
}
.filter-container {
display: flex;
height: 36px;
justify-content: space-between;
align-items: center;
margin: 22px 15px 15px 15px
margin: 15px
}
.user-count {
color: gray;
@ -281,7 +300,7 @@ export default {
}
.users-container {
h1 {
margin: 7px 10px 15px 10px;
margin: 0;
}
.actions-button {
width: 100%;
@ -296,6 +315,7 @@ export default {
}
.search {
width: 100%;
margin-left: 0;
}
.filter-container {
display: flex;
@ -315,6 +335,25 @@ export default {
padding-left: 8px;
}
}
.reboot-button {
margin: 0;
}
.users-header-container {
margin: 7px 10px 12px 10px;
}
.user-count {
color: gray;
font-size: 22px;
}
}
}
@media only screen and (max-width:801px) and (min-width: 481px) {
.actions-button {
width: 49%;
}
.search {
width: 49%;
}
}
</style>

View file

@ -1,15 +1,31 @@
<template>
<main v-if="!userProfileLoading">
<header v-if="isDesktop || isTablet" class="user-page-header">
<div class="avatar-name-container">
<el-avatar :src="user.avatar" size="large" />
<h1>{{ user.display_name }}</h1>
</div>
<div class="left-header-container">
<moderation-dropdown
:user="user"
:page="'userPage'"
@open-reset-token-dialog="openResetPasswordDialog"/>
<reboot-button/>
</div>
</header>
<div v-if="isMobile" class="user-page-header-container">
<header class="user-page-header">
<div class="avatar-name-container">
<el-avatar :src="user.avatar" size="large" />
<h1>{{ user.display_name }}</h1>
</div>
<reboot-button/>
</header>
<moderation-dropdown
:user="user"
:page="'userPage'"
@open-reset-token-dialog="openResetPasswordDialog"/>
</header>
</div>
<el-dialog
v-loading="loading"
:visible.sync="resetPasswordDialogOpen"
@ -104,10 +120,11 @@
import Status from '@/components/Status'
import ModerationDropdown from './components/ModerationDropdown'
import SecuritySettingsModal from './components/SecuritySettingsModal'
import RebootButton from '@/components/RebootButton'
export default {
name: 'UsersShow',
components: { ModerationDropdown, Status, SecuritySettingsModal },
components: { ModerationDropdown, RebootButton, Status, SecuritySettingsModal },
data() {
return {
showPrivate: false,
@ -116,6 +133,15 @@ export default {
}
},
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.users.loading
},
@ -142,6 +168,8 @@ export default {
}
},
mounted: function() {
this.$store.dispatch('NeedReboot')
this.$store.dispatch('GetNodeInfo')
this.$store.dispatch('FetchUserProfile', { userId: this.$route.params.id, godmode: false })
},
methods: {
@ -189,6 +217,11 @@ table {
width: 100%;
}
}
.left-header-container {
align-items: center;
display: flex;
justify-content: space-between;
}
.no-statuses {
margin-left: 28px;
color: #606266;
@ -198,6 +231,10 @@ table {
padding: 0;
width: 30%;
}
.reboot-button {
padding: 10px;
margin-left: 10px;
}
.recent-statuses-container {
display: flex;
flex-direction: column;
@ -229,7 +266,8 @@ table {
.user-page-header {
display: flex;
justify-content: space-between;
padding: 0 20px;
padding: 0 15px 0 20px;
align-items: center;
h1 {
display: inline
}
@ -264,10 +302,14 @@ table {
margin: 0 10px 20px 10px;
}
.user-page-header {
flex-direction: column;
align-items: flex-start;
padding: 0;
margin: 7px 0 15px 10px;
margin: 7px 15px 15px 10px;
}
.user-page-header-container {
.el-dropdown {
width: 95%;
margin: 0 15px 15px 10px;
}
}
.user-profile-card {
margin: 0 10px;
@ -282,9 +324,6 @@ table {
}
@media only screen and (max-width:801px) and (min-width: 481px) {
.avatar-name-container {
margin-bottom: 20px;
}
.recent-statuses {
margin: 20px 10px 15px 0;
}
@ -296,10 +335,8 @@ table {
margin: 0 10px 20px 0;
}
.user-page-header {
flex-direction: column;
align-items: flex-start;
padding: 0;
margin: 7px 0 20px 20px;
margin: 7px 15px 20px 20px;
}
.user-profile-card {
margin: 0 20px;

View file

@ -12,7 +12,9 @@ const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Element)
jest.mock('@/api/app')
jest.mock('@/api/invites')
jest.mock('@/api/nodeInfo')
describe('Invite tokens', () => {
let store

View file

@ -1,12 +1,14 @@
import app from '@/store/modules/app'
import user from '@/store/modules/user'
import invites from '@/store/modules/invites'
import settings from '@/store/modules/settings'
import getters from '@/store/getters'
export default {
modules: {
app,
invites,
settings,
user
},
getters

View file

@ -23,7 +23,9 @@ describe('Log out', () => {
store = new Vuex.Store(cloneDeep(storeConfig))
router = new VueRouter(cloneDeep(routerConfig))
router.beforeEach(beforeEachRoute)
window.location.reload = jest.fn()
delete window.location
window.location = { href: '' }
})
it('logs out user', async (done) => {

View file

@ -14,6 +14,7 @@ const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Element)
jest.mock('@/api/app')
jest.mock('@/api/reports')
describe('Reports', () => {

View file

@ -2,6 +2,7 @@ import app from '@/store/modules/app'
import user from '@/store/modules/user'
import users from '@/store/modules/users'
import reports from '@/store/modules/reports'
import settings from '@/store/modules/settings'
import status from '@/store/modules/status'
import getters from '@/store/getters'
@ -11,6 +12,7 @@ export default {
user,
users,
reports,
settings,
status
},
getters

View file

@ -16,12 +16,14 @@ localVue.use(Element)
describe('Settings search', () => {
let store
let actions
let appActions
beforeEach(() => {
actions = { ...settings.actions, FetchSettings: jest.fn() }
appActions = { ...app.actions, NeedReboot: jest.fn() }
actions = { ...settings.actions, FetchSettings: jest.fn(), GetNodeInfo: jest.fn() }
store = new Vuex.Store({
modules: {
app,
app: { ...app, actions: appActions },
settings: { ...settings, actions }
},
getters

View file

@ -14,6 +14,7 @@ const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Element)
jest.mock('@/api/app')
jest.mock('@/api/nodeInfo')
jest.mock('@/api/users')

View file

@ -1,4 +1,5 @@
import app from '@/store/modules/app'
import settings from '@/store/modules/settings'
import user from '@/store/modules/user'
import userProfile from '@/store/modules/userProfile'
import users from '@/store/modules/users'
@ -7,6 +8,7 @@ import getters from '@/store/getters'
export default {
modules: {
app,
settings,
user,
userProfile,
users

2290
yarn.lock

File diff suppressed because it is too large Load diff