Show reboot button on every page

This commit is contained in:
Angelina Filippova 2020-04-17 22:27:00 +00:00
parent 66c5a85821
commit 655584c877
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 - 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 ### Fixed
- Disable Invites tab when invites are disabled on BE - Disable Invites tab when invites are disabled on BE

View file

@ -81,7 +81,7 @@
"autoprefixer": "8.5.0", "autoprefixer": "8.5.0",
"babel-eslint": "8.2.6", "babel-eslint": "8.2.6",
"babel-helper-vue-jsx-merge-props": "2.0.3", "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-loader": "^8.0.5",
"babel-plugin-dynamic-import-node-babel-7": "^2.0.7", "babel-plugin-dynamic-import-node-babel-7": "^2.0.7",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
@ -101,7 +101,7 @@
"hash-sum": "1.0.2", "hash-sum": "1.0.2",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"husky": "0.14.3", "husky": "0.14.3",
"jest": "^24.1.0", "jest": "^25.3.0",
"jest-transform-stub": "^2.0.0", "jest-transform-stub": "^2.0.0",
"lint-staged": "7.2.2", "lint-staged": "7.2.2",
"mini-css-extract-plugin": "0.4.1", "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 }) 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) { export async function fetchUsers(filters, authHost, token, page = 1) {
const filteredUsers = filterUsers(filters) const filteredUsers = filterUsers(filters)
return Promise.resolve({ data: { 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()}` } : {} 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', emoji: 'Emoji',
markup: 'Markup settings', markup: 'Markup settings',
corsPlug: 'CORS plug config', corsPlug: 'CORS plug config',
instanceReboot: 'Instance Reboot', instanceReboot: 'Reboot Instance',
restartApp: 'You must restart the instance to apply settings', restartApp: 'You must restart the instance to apply settings',
restartSuccess: 'Instance rebooted successfully!' restartSuccess: 'Instance rebooted successfully!'
}, },

View file

@ -1,4 +1,5 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { needReboot, restartApp } from '@/api/app'
const app = { const app = {
state: { state: {
@ -8,6 +9,7 @@ const app = {
}, },
device: 'desktop', device: 'desktop',
language: Cookies.get('language') || 'en', language: Cookies.get('language') || 'en',
needReboot: false,
size: Cookies.get('size') || 'medium', size: Cookies.get('size') || 'medium',
invitesEnabled: false invitesEnabled: false
}, },
@ -36,20 +38,25 @@ const app = {
state.language = language state.language = language
Cookies.set('language', language) Cookies.set('language', language)
}, },
TOGGLE_REBOOT: (state, needReboot) => {
state.needReboot = needReboot
},
SET_SIZE: (state, size) => { SET_SIZE: (state, size) => {
state.size = size state.size = size
Cookies.set('size', size) Cookies.set('size', size)
} }
}, },
actions: { actions: {
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
},
closeSideBar({ commit }, { withoutAnimation }) { closeSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation) commit('CLOSE_SIDEBAR', withoutAnimation)
}, },
toggleDevice({ commit }, device) { async NeedReboot({ commit, getters }) {
commit('TOGGLE_DEVICE', device) 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) { SetInvitesEnabled({ commit }, invitesEnabled) {
commit('SET_INVITES_ENABLED', invitesEnabled) commit('SET_INVITES_ENABLED', invitesEnabled)
@ -59,6 +66,12 @@ const app = {
}, },
setSize({ commit }, size) { setSize({ commit }, size) {
commit('SET_SIZE', 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 { checkPartialUpdate, formSearchObject, parseNonTuples, parseTuples, valueHasTuples, wrapUpdatedSettings } from './normalizers'
import _ from 'lodash' import _ from 'lodash'
@ -9,7 +9,6 @@ const settings = {
db: {}, db: {},
description: [], description: [],
loading: true, loading: true,
needReboot: false,
searchData: {}, searchData: {},
settings: {}, settings: {},
updatedSettings: {} updatedSettings: {}
@ -55,9 +54,6 @@ const settings = {
state.settings = newSettings state.settings = newSettings
state.db = newDbSettings state.db = newDbSettings
}, },
TOGGLE_REBOOT: (state, needReboot) => {
state.needReboot = needReboot || false
},
TOGGLE_TABS: (state, status) => { TOGGLE_TABS: (state, status) => {
state.configDisabled = status state.configDisabled = status
}, },
@ -84,7 +80,6 @@ const settings = {
const searchObject = formSearchObject(description.data) const searchObject = formSearchObject(description.data)
commit('SET_SEARCH', searchObject) commit('SET_SEARCH', searchObject)
commit('SET_SETTINGS', response.data.configs) commit('SET_SETTINGS', response.data.configs)
commit('TOGGLE_REBOOT', response.data.need_reboot)
} catch (_e) { } catch (_e) {
commit('TOGGLE_TABS', true) commit('TOGGLE_TABS', true)
commit('SET_ACTIVE_TAB', 'relays') commit('SET_ACTIVE_TAB', 'relays')
@ -102,10 +97,6 @@ const settings = {
commit('TOGGLE_REBOOT', response.data.need_reboot) commit('TOGGLE_REBOOT', response.data.need_reboot)
commit('REMOVE_SETTING_FROM_UPDATED', { group, key, subkeys: subkeys || [] }) 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) { SetActiveTab({ commit }, tab) {
commit('SET_ACTIVE_TAB', tab) commit('SET_ACTIVE_TAB', tab)
}, },

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,12 +16,14 @@ localVue.use(Element)
describe('Settings search', () => { describe('Settings search', () => {
let store let store
let actions let actions
let appActions
beforeEach(() => { 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({ store = new Vuex.Store({
modules: { modules: {
app, app: { ...app, actions: appActions },
settings: { ...settings, actions } settings: { ...settings, actions }
}, },
getters getters

View file

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

View file

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

2290
yarn.lock

File diff suppressed because it is too large Load diff