Merge branch 'feature/reduce-nav-sidebars' into develop

This commit is contained in:
Angelina Filippova 2021-03-19 20:50:14 +03:00
commit b1ce85fd33
64 changed files with 782 additions and 419 deletions

View file

@ -28,6 +28,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Replace regular inputs with textareas for setting welcome messages in the Settings section - Replace regular inputs with textareas for setting welcome messages in the Settings section
- Update rendering Moderation Log Messages so that all usernames are links to the pages of the corresponding users in Admin-FE - Update rendering Moderation Log Messages so that all usernames are links to the pages of the corresponding users in Admin-FE
- Remove Websocket based federation settings - Remove Websocket based federation settings
- Move Settings tab navigation from the tabbed menu to the main sidebar menu. A separate route is created for each tab.
- Move Emoji packs configuration to the Emoji tab in the Settings section
- 401 and 404 error pages updated - 401 and 404 error pages updated
- Remove unused components - Remove unused components

View file

@ -69,7 +69,7 @@
"vue": "^2.6.8", "vue": "^2.6.8",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-i18n": "^8.9.0", "vue-i18n": "^8.9.0",
"vue-router": "3.0.2", "vue-router": "^3.5.1",
"vue-splitpane": "1.0.2", "vue-splitpane": "1.0.2",
"vuedraggable": "^2.16.0", "vuedraggable": "^2.16.0",
"vuex": "3.0.1", "vuex": "3.0.1",

View file

@ -15,7 +15,16 @@ export async function deleteInstanceDocument(name, authHost, token) {
export async function fetchDescription(authHost, token) { export async function fetchDescription(authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/config/descriptions`, url: `/api/v1/pleroma/admin/config/descriptions`,
method: 'get',
headers: authHeaders(token)
})
}
export async function fetchDescription2(authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/v2/pleroma/admin/config/descriptions`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })

View file

@ -70,6 +70,7 @@ export default {
chats: 'Chats', chats: 'Chats',
settings: 'Settings', settings: 'Settings',
moderationLog: 'Moderation Log', moderationLog: 'Moderation Log',
relays: 'Relays',
mediaProxyCache: 'MediaProxy Cache', mediaProxyCache: 'MediaProxy Cache',
'emoji-packs': 'Emoji packs' 'emoji-packs': 'Emoji packs'
}, },
@ -426,6 +427,7 @@ export default {
activityPub: 'ActivityPub', activityPub: 'ActivityPub',
auth: 'Authentication', auth: 'Authentication',
captcha: 'Captcha', captcha: 'Captcha',
emoji: 'Emoji',
frontend: 'Frontend', frontend: 'Frontend',
http: 'HTTP', http: 'HTTP',
mrf: 'MRF', mrf: 'MRF',
@ -437,11 +439,6 @@ export default {
esshd: 'BBS / SSH access', esshd: 'BBS / SSH access',
rateLimiters: 'Rate limiters', rateLimiters: 'Rate limiters',
other: 'Other', other: 'Other',
relays: 'Relays',
follow: 'Follow',
followRelay: 'Follow new relay',
followedBack: 'Followed Back',
instanceUrl: 'Instance URL',
success: 'Settings changed successfully!', success: 'Settings changed successfully!',
description: 'Description', description: 'Description',
removeFromDB: 'Remove setting from the DB', removeFromDB: 'Remove setting from the DB',
@ -483,6 +480,13 @@ export default {
frontendStartedInstallation: 'Installation started', frontendStartedInstallation: 'Installation started',
inProcess: 'In process' inProcess: 'In process'
}, },
relays: {
relays: 'Relays',
follow: 'Follow',
followRelay: 'Follow new relay',
followedBack: 'Followed Back',
instanceUrl: 'Instance URL'
},
invites: { invites: {
inviteTokens: 'Invite tokens', inviteTokens: 'Invite tokens',
createInviteToken: 'Generate invite token', createInviteToken: 'Generate invite token',

View file

@ -28,7 +28,7 @@ export const beforeEachRoute = (to, from, next) => {
store.dispatch('GetUserInfo').then(res => { store.dispatch('GetUserInfo').then(res => {
const roles = res.data.pleroma.is_admin ? ['admin'] : [] const roles = res.data.pleroma.is_admin ? ['admin'] : []
store.dispatch('GenerateRoutes', { roles }).then(() => { store.dispatch('GenerateRoutes', { roles }).then(() => {
router.addRoutes(store.getters.addRouters) store.getters.addRouters.forEach(route => router.addRoute(route))
next({ ...to, replace: true }) next({ ...to, replace: true })
}) })
}).catch((err) => { }).catch((err) => {

View file

@ -21,19 +21,26 @@ import Layout from '@/views/layout/Layout'
const disabledFeatures = process.env.DISABLED_FEATURES || [] const disabledFeatures = process.env.DISABLED_FEATURES || []
const settingsDisabled = disabledFeatures.includes('settings') const settingsDisabled = disabledFeatures.includes('settings')
const settingsChildren = () => {
return localStorage.getItem('settingsTabs')
? JSON.parse(localStorage.getItem('settingsTabs')).map(({ label, path }) => {
return {
path,
component: () => import(`@/views/settings`),
name: label,
meta: { title: label }
}
})
: []
}
const settings = { const settings = {
path: '/settings', path: '/settings',
component: Layout, component: Layout,
children: [ name: 'Settings',
{ hasSubmenu: true,
path: 'index', meta: { title: 'settings', icon: 'el-icon-setting', noCache: true },
component: () => import('@/views/settings/index'), children: settingsChildren()
name: 'Settings',
meta: { title: 'settings', icon: 'settings', noCache: true }
}
]
} }
const statusesDisabled = disabledFeatures.includes('statuses') const statusesDisabled = disabledFeatures.includes('statuses')
const statuses = { const statuses = {
path: '/statuses', path: '/statuses',
@ -43,7 +50,7 @@ const statuses = {
path: 'index', path: 'index',
component: () => import('@/views/statuses/index'), component: () => import('@/views/statuses/index'),
name: 'Statuses', name: 'Statuses',
meta: { title: 'statuses', icon: 'form', noCache: true } meta: { title: 'statuses', icon: 'el-icon-chat-line-square', noCache: true }
} }
] ]
} }
@ -57,7 +64,7 @@ const reports = {
path: 'index', path: 'index',
component: () => import('@/views/reports/index'), component: () => import('@/views/reports/index'),
name: 'Reports', name: 'Reports',
meta: { title: 'reports', icon: 'documentation', noCache: true } meta: { title: 'reports', icon: 'el-icon-receiving', noCache: true }
} }
] ]
} }
@ -71,21 +78,21 @@ const invites = {
path: 'index', path: 'index',
component: () => import('@/views/invites/index'), component: () => import('@/views/invites/index'),
name: 'Invites', name: 'Invites',
meta: { title: 'invites', icon: 'guide', noCache: true } meta: { title: 'invites', icon: 'el-icon-postcard', noCache: true }
} }
] ]
} }
const emojiPacksDisabled = disabledFeatures.includes('emoji-packs') const relaysDisabled = disabledFeatures.includes('relays')
const emojiPacks = { const relays = {
path: '/emoji_packs', path: '/relays',
component: Layout, component: Layout,
children: [ children: [
{ {
path: 'index', path: 'index',
component: () => import('@/views/emojiPacks/index'), component: () => import('@/views/relays/index'),
name: 'Emoji Packs', name: 'Relays',
meta: { title: 'emoji-packs', icon: 'eye-open', noCache: true } meta: { title: 'relays', icon: 'el-icon-connection', noCache: true }
} }
] ]
} }
@ -99,7 +106,7 @@ const moderationLog = {
path: 'index', path: 'index',
component: () => import('@/views/moderationLog/index'), component: () => import('@/views/moderationLog/index'),
name: 'Moderation Log', name: 'Moderation Log',
meta: { title: 'moderationLog', icon: 'list', noCache: true } meta: { title: 'moderationLog', icon: 'el-icon-notebook-2', noCache: true }
} }
] ]
} }
@ -113,7 +120,7 @@ const mediaProxyCache = {
path: 'index', path: 'index',
component: () => import('@/views/mediaProxyCache/index'), component: () => import('@/views/mediaProxyCache/index'),
name: 'MediaProxy Cache', name: 'MediaProxy Cache',
meta: { title: 'mediaProxyCache', icon: 'example', noCache: true } meta: { title: 'mediaProxyCache', icon: 'el-icon-coin', noCache: true }
} }
] ]
} }
@ -158,7 +165,8 @@ export const constantRouterMap = [
{ {
path: '', path: '',
component: Layout, component: Layout,
redirect: '/users/index' redirect: '/users/index',
hidden: true
} }
] ]
@ -177,15 +185,15 @@ export const asyncRouterMap = [
path: 'index', path: 'index',
component: () => import('@/views/users/index'), component: () => import('@/views/users/index'),
name: 'Users', name: 'Users',
meta: { title: 'users', icon: 'peoples', noCache: true } meta: { title: 'users', icon: 'el-icon-user', noCache: true }
} }
] ]
}, },
...(statusesDisabled ? [] : [statuses]), ...(statusesDisabled ? [] : [statuses]),
...(reportsDisabled ? [] : [reports]), ...(reportsDisabled ? [] : [reports]),
...(invitesDisabled ? [] : [invites]), ...(invitesDisabled ? [] : [invites]),
...(emojiPacksDisabled ? [] : [emojiPacks]),
...(moderationLogDisabled ? [] : [moderationLog]), ...(moderationLogDisabled ? [] : [moderationLog]),
...(relaysDisabled ? [] : [relays]),
...(mediaProxyCacheDisabled ? [] : [mediaProxyCache]), ...(mediaProxyCacheDisabled ? [] : [mediaProxyCache]),
...(settingsDisabled ? [] : [settings]), ...(settingsDisabled ? [] : [settings]),
{ {

View file

@ -17,6 +17,7 @@ const getters = {
errorLogs: state => state.errorLog.logs, errorLogs: state => state.errorLog.logs,
users: state => state.users.fetchedUsers, users: state => state.users.fetchedUsers,
authHost: state => state.user.authHost, authHost: state => state.user.authHost,
settings: state => state.settings settings: state => state.settings,
tabs: state => state.settings.tabs
} }
export default getters export default getters

View file

@ -46,15 +46,10 @@ const permission = {
} }
}, },
actions: { actions: {
GenerateRoutes({ commit }, data) { GenerateRoutes({ commit }, { roles, _routesWithSettings }) {
return new Promise(resolve => { return new Promise(resolve => {
const { roles } = data const routes = _routesWithSettings || asyncRouterMap
let accessedRouters const accessedRouters = roles.includes('admin') ? routes : filterAsyncRouter(asyncRouterMap, roles)
if (roles.includes('admin')) {
accessedRouters = asyncRouterMap
} else {
accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
}
commit('SET_ROUTERS', accessedRouters) commit('SET_ROUTERS', accessedRouters)
resolve() resolve()
}) })

View file

@ -9,11 +9,11 @@ import {
updateInstanceDocument, updateInstanceDocument,
updateSettings } from '@/api/settings' updateSettings } from '@/api/settings'
import { formSearchObject, parseNonTuples, parseTuples, valueHasTuples, wrapUpdatedSettings } from './normalizers' import { formSearchObject, parseNonTuples, parseTuples, valueHasTuples, wrapUpdatedSettings } from './normalizers'
import { tabs } from '../../utils/tabs'
import _ from 'lodash' import _ from 'lodash'
const settings = { const settings = {
state: { state: {
activeTab: 'instance',
configDisabled: true, configDisabled: true,
frontends: [], frontends: [],
db: {}, db: {},
@ -21,7 +21,9 @@ const settings = {
instancePanel: '', instancePanel: '',
loading: true, loading: true,
searchData: {}, searchData: {},
searchQuery: '',
settings: {}, settings: {},
tabs: [],
termsOfServices: '', termsOfServices: '',
updatedSettings: {} updatedSettings: {}
}, },
@ -38,9 +40,6 @@ const settings = {
state.updatedSettings = updatedSettings state.updatedSettings = updatedSettings
} }
}, },
SET_ACTIVE_TAB: (state, tab) => {
state.activeTab = tab
},
SET_DESCRIPTION: (state, data) => { SET_DESCRIPTION: (state, data) => {
state.description = data state.description = data
}, },
@ -53,6 +52,9 @@ const settings = {
SET_SEARCH: (state, searchObject) => { SET_SEARCH: (state, searchObject) => {
state.searchData = searchObject state.searchData = searchObject
}, },
SET_SEARCH_QUERY: (state, query) => {
state.searchQuery = query
},
SET_SETTINGS: (state, data) => { SET_SETTINGS: (state, data) => {
const newSettings = data.reduce((acc, { group, key, value }) => { const newSettings = data.reduce((acc, { group, key, value }) => {
const parsedValue = valueHasTuples(key, value) const parsedValue = valueHasTuples(key, value)
@ -72,6 +74,9 @@ const settings = {
state.settings = newSettings state.settings = newSettings
state.db = newDbSettings state.db = newDbSettings
}, },
SET_TABS: (state, tabs) => {
state.tabs = tabs
},
SET_TERMS_OF_SERVICES: (state, data) => { SET_TERMS_OF_SERVICES: (state, data) => {
state.termsOfServices = data state.termsOfServices = data
}, },
@ -107,15 +112,16 @@ const settings = {
async FetchSettings({ commit, getters }) { async FetchSettings({ commit, getters }) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
try { try {
const response = await fetchSettings(getters.authHost, getters.token) const settings = await fetchSettings(getters.authHost, getters.token)
const description = await fetchDescription(getters.authHost, getters.token) commit('SET_SETTINGS', settings.data.configs)
commit('SET_DESCRIPTION', description.data)
const searchObject = formSearchObject(description.data) const { data } = await fetchDescription(getters.authHost, getters.token)
commit('SET_DESCRIPTION', data)
const searchObject = formSearchObject(data)
commit('SET_SEARCH', searchObject) commit('SET_SEARCH', searchObject)
commit('SET_SETTINGS', response.data.configs) commit('SET_TABS', tabs)
} catch (_e) { } catch (_e) {
commit('TOGGLE_TABS', true) commit('TOGGLE_TABS', true)
commit('SET_ACTIVE_TAB', 'relays')
commit('SET_LOADING', false) commit('SET_LOADING', false)
return return
} }
@ -138,8 +144,8 @@ 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 || [] })
}, },
SetActiveTab({ commit }, tab) { SetSearchQuery({ commit }, query) {
commit('SET_ACTIVE_TAB', tab) commit('SET_SEARCH_QUERY', query)
}, },
async SubmitChanges({ getters, commit, state }) { async SubmitChanges({ getters, commit, state }) {
const configs = Object.keys(state.updatedSettings).reduce((acc, group) => { const configs = Object.keys(state.updatedSettings).reduce((acc, group) => {

View file

@ -91,7 +91,7 @@
} }
.submenu-title-noDropdown { .submenu-title-noDropdown {
padding-left: 10px !important; padding-left: 8px !important;
position: relative; position: relative;
.el-tooltip { .el-tooltip {

View file

@ -19,7 +19,7 @@ $menuHover:#263445;
$subMenuBg:#1f2d3d; $subMenuBg:#1f2d3d;
$subMenuHover:#001528; $subMenuHover:#001528;
$sideBarWidth: 180px; $sideBarWidth: 205px;
// the :export directive is the magic sauce for webpack // the :export directive is the magic sauce for webpack
:export { :export {

22
src/utils/tabs.js Normal file
View file

@ -0,0 +1,22 @@
export const tabs = [
{ label: 'ActivityPub', path: 'activity-pub', tab: ':activity_pub' },
{ label: 'Authentication', path: 'authentication', tab: ':authentication' },
{ label: 'Captcha', path: 'captcha', tab: ':captcha' },
{ label: 'BBS / SSH access', path: 'esshd', tab: ':esshd' },
{ label: 'Emoji', path: 'emoji', tab: ':emoji' },
{ label: 'Frontend', path: 'frontend', tab: ':frontend' },
{ label: 'Gopher', path: 'gopher', tab: ':gopher' },
{ label: 'HTTP', path: 'http', tab: ':http' },
{ label: 'Instance', path: 'instance', tab: ':instance' },
{ label: 'Job queue', path: 'job-queue', tab: ':job_queue' },
{ label: 'Link Formatter', path: 'link-formatter', tab: ':link_formatter' },
{ label: 'Logger', path: 'logger', tab: ':logger' },
{ label: 'Mailer', path: 'mailer', tab: ':mailer' },
{ label: 'Media Proxy', path: 'media-proxy', tab: ':media_proxy' },
{ label: 'Metadata', path: 'metadata', tab: ':metadata' },
{ label: 'MRF', path: 'mrf', tab: ':mrf' },
{ label: 'Rate limiters', path: 'rate-limiters', tab: ':rate_limiters' },
{ label: 'Web push encryption', path: 'web-push', tab: ':web_push' },
{ label: 'Upload', path: 'upload', tab: ':upload' },
{ label: 'Other', path: 'other', tab: ':other' }
]

View file

@ -1,9 +1,9 @@
<template> <template>
<span> <div>
<svg-icon :icon-class="icon"/> <i v-if="icon" :class="icon" class="menu-item-icon"/>
<span slot="title">{{ title }}</span> <span slot="title">{{ title }}</span>
<el-badge :value="count" type="primary" class="count-badge" /> <el-badge :value="count" type="primary" class="count-badge" />
</span> </div>
</template> </template>
<script> <script>
@ -31,4 +31,11 @@ export default {
margin-left: 5px; margin-left: 5px;
height: 48px; height: 48px;
} }
.menu-item-icon {
margin-right: 5px;
width: 18px;
text-align: center;
font-size: 18px;
vertical-align: middle;
}
</style> </style>

View file

@ -1,7 +1,7 @@
<template> <template>
<div v-if="!item.hidden && item.children && invitesEnabled" class="menu-wrapper"> <div v-if="!item.hidden && invitesEnabled" class="menu-wrapper">
<template
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> v-if="item.children && hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
<app-link :to="resolvePath(onlyOneChild.path)"> <app-link :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
<item <item
@ -12,7 +12,7 @@
</el-menu-item> </el-menu-item>
</app-link> </app-link>
</template> </template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)"> <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" :id="item.meta.title">
<template slot="title"> <template slot="title">
<item <item
v-if="item.meta" v-if="item.meta"
@ -32,7 +32,7 @@
class="nest-menu" /> class="nest-menu" />
<app-link v-else :to="resolvePath(child.path)" :key="child.name"> <app-link v-else :to="resolvePath(child.path)" :key="child.name">
<el-menu-item :index="resolvePath(child.path)"> <el-menu-item :index="resolvePath(child.path)" class="submenu-item">
<item <item
v-if="child.meta" v-if="child.meta"
:count="showCount(item) ? normalizedReportsCount : null" :count="showCount(item) ? normalizedReportsCount : null"
@ -90,14 +90,14 @@ export default {
}, },
methods: { methods: {
hasOneShowingChild(children, parent) { hasOneShowingChild(children, parent) {
if (parent.hasSubmenu) {
return false
}
const showingChildren = children.filter(item => { const showingChildren = children.filter(item => {
if (item.hidden) { // Temp set(will be used if only has one showing child)
return false this.onlyOneChild = item
} else { return true
// Temp set(will be used if only has one showing child)
this.onlyOneChild = item
return true
}
}) })
// When there is only one child router, the child router is displayed by default // When there is only one child router, the child router is displayed by default
@ -129,3 +129,9 @@ export default {
} }
} }
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped>
.submenu-item {
padding-left: 54px !important;
}
</style>

View file

@ -7,6 +7,7 @@
:text-color="variables.menuText" :text-color="variables.menuText"
:active-text-color="variables.menuActiveText" :active-text-color="variables.menuActiveText"
mode="vertical" mode="vertical"
@open="handleOpen"
> >
<sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path"/> <sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path"/>
</el-menu> </el-menu>
@ -17,13 +18,17 @@
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import SidebarItem from './SidebarItem' import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss' import variables from '@/styles/variables.scss'
import router from '@/router'
import { asyncRouterMap } from '@/router'
export default { export default {
components: { SidebarItem }, components: { SidebarItem },
computed: { computed: {
...mapGetters([ ...mapGetters([
'permission_routers', 'permission_routers',
'sidebar' 'roles',
'sidebar',
'tabs'
]), ]),
variables() { variables() {
return variables return variables
@ -34,6 +39,49 @@ export default {
}, },
mounted() { mounted() {
this.$store.dispatch('FetchOpenReportsCount') this.$store.dispatch('FetchOpenReportsCount')
},
methods: {
getMergedRoutes() {
const routes = router.getRoutes().filter(item => !item.hidden)
return routes.reduce((acc, element) => {
if (!element.parent || element.parent.path !== '/settings') {
return acc
} else {
const index = acc.findIndex(route => route.path === '/settings')
acc[index] = { ...acc[index], children: [...acc[index].children, element] }
return acc
}
}, [...asyncRouterMap])
},
async handleOpen($event) {
if ($event === '/settings') {
if (!localStorage.getItem('settingsTabs')) {
await this.$store.dispatch('FetchSettings')
const menuItems = this.tabs
localStorage.setItem('settingsTabs', JSON.stringify(menuItems))
menuItems.forEach(({ label, path }) => {
router.addRoute('Settings', {
path,
component: () => import(`@/views/settings`),
name: label,
meta: { title: label }
})
})
const routes = this.getMergedRoutes()
this.$store.dispatch('GenerateRoutes', { roles: this.roles, _routesWithSettings: routes })
}
let isRequesting = true
const step = () => {
document.querySelector('#settings').scrollIntoView({ block: 'start', behavior: 'smooth' })
if (isRequesting) requestAnimationFrame(step)
}
requestAnimationFrame(step)
setTimeout(() => {
isRequesting = false
}, 300) // this equals to the hide-timeout of the el-submenu
}
}
} }
} }
</script> </script>

View file

@ -197,9 +197,6 @@ h1 {
.router-link { .router-link {
text-decoration: none; text-decoration: none;
} }
.search-container {
text-align: right;
}
.pagination { .pagination {
text-align: center; text-align: center;
} }

View file

@ -1,15 +1,21 @@
<template> <template>
<div v-if="!loading" class="relays-container"> <div v-if="!loading" class="relays-container">
<div class="relays-header-container">
<h1>
{{ $t('relays.relays') }}
</h1>
<reboot-button/>
</div>
<div class="follow-relay-container"> <div class="follow-relay-container">
<el-input v-model="newRelay" :placeholder="$t('settings.followRelay')" class="follow-relay" @keyup.enter.native="followRelay"/> <el-input v-model="newRelay" :placeholder="$t('relays.followRelay')" class="follow-relay" @keyup.enter.native="followRelay"/>
<el-button @click.native="followRelay">{{ $t('settings.follow') }}</el-button> <el-button @click.native="followRelay">{{ $t('relays.follow') }}</el-button>
</div> </div>
<el-table :data="relays"> <el-table :data="relays">
<el-table-column <el-table-column
:label="$t('settings.instanceUrl')" :label="$t('relays.instanceUrl')"
prop="actor"/> prop="actor"/>
<el-table-column <el-table-column
:label="$t('settings.followedBack')" :label="$t('relays.followedBack')"
:width="getLabelWidth" :width="getLabelWidth"
prop="followed_back" prop="followed_back"
align="center"> align="center">
@ -32,8 +38,11 @@
</template> </template>
<script> <script>
import RebootButton from '@/components/RebootButton'
export default { export default {
name: 'Relays', name: 'Relays',
components: { RebootButton },
data() { data() {
return { return {
newRelay: '' newRelay: ''
@ -70,5 +79,5 @@ export default {
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../styles/main';
@include settings @include relays
</style> </style>

View file

@ -56,6 +56,9 @@ export default {
loading() { loading() {
return this.$store.state.settings.loading return this.$store.state.settings.loading
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
user() { user() {
return this.settings.description.find(setting => setting.key === ':user') return this.settings.description.find(setting => setting.key === ':user')
}, },
@ -63,6 +66,15 @@ export default {
return _.get(this.settings.settings, [':pleroma', ':user']) || {} return _.get(this.settings.settings, [':pleroma', ':user']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -80,6 +92,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -81,6 +81,18 @@ export default {
}, },
pleromaAuthenticatorData() { pleromaAuthenticatorData() {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Auth.Authenticator']) || {} return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Auth.Authenticator']) || {}
},
searchQuery() {
return this.$store.state.settings.searchQuery
}
},
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
} }
}, },
methods: { methods: {
@ -100,6 +112,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -61,6 +61,18 @@ export default {
}, },
loading() { loading() {
return this.settings.loading return this.settings.loading
},
searchQuery() {
return this.$store.state.settings.searchQuery
}
},
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
} }
}, },
methods: { methods: {
@ -80,6 +92,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -1,9 +1,5 @@
<template> <template>
<div class="emoji-packs"> <div class="emoji-packs">
<div class="emoji-packs-header">
<h1>{{ $t('emoji.emojiPacks') }}</h1>
<reboot-button/>
</div>
<div class="emoji-header-container"> <div class="emoji-header-container">
<div class="emoji-packs-header-button-container"> <div class="emoji-packs-header-button-container">
<el-button class="reload-emoji-button" @click="reloadEmoji">{{ $t('emoji.reloadEmoji') }}</el-button> <el-button class="reload-emoji-button" @click="reloadEmoji">{{ $t('emoji.reloadEmoji') }}</el-button>
@ -15,7 +11,7 @@
</div> </div>
</div> </div>
<el-tabs v-model="activeTab" type="card" class="emoji-packs-tabs"> <el-tabs v-model="activeTab" type="card" class="emoji-packs-tabs">
<el-tab-pane :label="$t('emoji.localPacks')" name="local"> <el-tab-pane v-if="!emojiPacksDisabled" :label="$t('emoji.localPacks')" name="local">
<el-form :label-width="labelWidth" class="emoji-packs-form"> <el-form :label-width="labelWidth" class="emoji-packs-form">
<el-form-item :label="$t('emoji.localPacks')"> <el-form-item :label="$t('emoji.localPacks')">
<el-button @click="refreshLocalPacks">{{ $t('emoji.refreshLocalPacks') }}</el-button> <el-button @click="refreshLocalPacks">{{ $t('emoji.refreshLocalPacks') }}</el-button>
@ -49,7 +45,7 @@
/> />
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('emoji.remotePacks')" name="remote"> <el-tab-pane v-if="!emojiPacksDisabled" :label="$t('emoji.remotePacks')" name="remote">
<el-form :label-width="labelWidth" class="emoji-packs-form"> <el-form :label-width="labelWidth" class="emoji-packs-form">
<el-form-item :label="$t('emoji.remotePacks')"> <el-form-item :label="$t('emoji.remotePacks')">
<div class="create-pack"> <div class="create-pack">
@ -82,18 +78,31 @@
/> />
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('settings.settings')" name="settings">
<div v-if="!loading" :class="isSidebarOpen" class="form-container">
<el-form :model="emojiData" :label-position="labelPosition" :label-width="settingsLabelWidth">
<setting :setting-group="emoji" :data="emojiData"/>
</el-form>
<div class="submit-button-container">
<el-button class="submit-button" type="primary" @click="onSubmit">Submit</el-button>
</div>
</div>
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</template> </template>
<script> <script>
import LocalEmojiPack from './components/LocalEmojiPack' import { mapGetters } from 'vuex'
import RemoteEmojiPack from './components/RemoteEmojiPack'
import i18n from '@/lang' import i18n from '@/lang'
import RebootButton from '@/components/RebootButton' import LocalEmojiPack from '../../emojiPacks/LocalEmojiPack'
import RemoteEmojiPack from '../../emojiPacks/RemoteEmojiPack'
import Setting from './Setting'
import _ from 'lodash'
export default { export default {
components: { LocalEmojiPack, RebootButton, RemoteEmojiPack }, name: 'Emoji',
components: { LocalEmojiPack, RemoteEmojiPack, Setting },
data() { data() {
return { return {
activeTab: 'local', activeTab: 'local',
@ -104,18 +113,37 @@ export default {
} }
}, },
computed: { computed: {
...mapGetters([
'settings'
]),
currentLocalPacksPage() { currentLocalPacksPage() {
return this.$store.state.emojiPacks.currentLocalPacksPage return this.$store.state.emojiPacks.currentLocalPacksPage
}, },
currentRemotePacksPage() { currentRemotePacksPage() {
return this.$store.state.emojiPacks.currentRemotePacksPage return this.$store.state.emojiPacks.currentRemotePacksPage
}, },
emoji() {
return this.settings.description.find(setting => setting.key === ':emoji')
},
emojiData() {
return _.get(this.settings.settings, [':pleroma', ':emoji']) || {}
},
emojiPacksDisabled() {
const disabledFeatures = process.env.DISABLED_FEATURES || []
return disabledFeatures.includes('emoji-packs')
},
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'
}, },
labelPosition() {
return this.isMobile ? 'top' : 'right'
},
labelWidth() { labelWidth() {
if (this.isMobile) { if (this.isMobile) {
return '105px' return '105px'
@ -125,6 +153,9 @@ export default {
return '200px' return '200px'
} }
}, },
loading() {
return this.settings.loading
},
localPacks() { localPacks() {
return this.$store.state.emojiPacks.localPacks return this.$store.state.emojiPacks.localPacks
}, },
@ -147,12 +178,35 @@ export default {
}, },
remotePacksCount() { remotePacksCount() {
return this.$store.state.emojiPacks.remotePacksCount return this.$store.state.emojiPacks.remotePacksCount
},
searchQuery() {
return this.$store.state.settings.searchQuery
},
settingsLabelWidth() {
if (this.isMobile) {
return '120px'
} else if (this.isTablet) {
return '200px'
} else {
return '280px'
}
} }
}, },
mounted() { mounted() {
this.$store.dispatch('GetNodeInfo') this.$store.dispatch('GetNodeInfo')
this.$store.dispatch('NeedReboot') this.$store.dispatch('NeedReboot')
this.refreshLocalPacks() this.refreshLocalPacks()
if (this.searchQuery.length > 0) {
this.activeTab = 'settings'
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
console.log(selectedSetting)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
}, },
methods: { methods: {
closeLocalTabs() { closeLocalTabs() {
@ -193,6 +247,17 @@ export default {
this.$store.dispatch('ReloadEmoji') this.$store.dispatch('ReloadEmoji')
}) })
}, },
async onSubmit() {
try {
await this.$store.dispatch('SubmitChanges')
} catch (e) {
return
}
this.$message({
type: 'success',
message: i18n.t('settings.success')
})
},
refreshLocalPacks() { refreshLocalPacks() {
try { try {
this.$store.dispatch('FetchLocalEmojiPacks', this.currentLocalPacksPage) this.$store.dispatch('FetchLocalEmojiPacks', this.currentLocalPacksPage)
@ -225,120 +290,7 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
.create-pack { @import '../../styles/settings';
display: flex; @include settings;
justify-content: space-between @include emoji;
}
.create-pack-button {
margin-left: 10px;
}
.emoji-header-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 15px 22px 15px;
}
.emoji-name-warning {
color: #666666;
font-size: 13px;
line-height: 22px;
margin: 5px 0 0 0;
overflow-wrap: break-word;
overflow: hidden;
text-overflow: ellipsis;
}
.emoji-packs-header-button-container {
display: flex;
}
.emoji-packs-form {
margin-top: 15px;
}
.emoji-packs-header {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 15px 15px 15px;
}
.emoji-packs-tabs {
margin: 0 15px 15px 15px;
}
.import-pack-button {
margin-left: 10px;
width: 30%;
max-width: 700px;
}
h1 {
margin: 0;
}
.line {
width: 100%;
height: 0;
border: 1px solid #eee;
margin-bottom: 22px;
}
.pagination {
margin: 25px 0;
text-align: center;
}
.reboot-button {
padding: 10px;
margin: 0;
width: 145px;
}
@media only screen and (min-width: 1824px) {
.emoji-packs {
max-width: 1824px;
margin: auto;
}
}
@media only screen and (max-width:480px) {
.create-pack {
height: 82px;
flex-direction: column;
}
.create-pack-button {
margin-left: 0;
}
.divider {
margin: 15px 0;
}
.el-message {
min-width: 80%;
}
.el-message-box {
width: 80%;
}
.emoji-header-container {
flex-direction: column;
align-items: flex-start;
}
.emoji-packs-form {
margin: 0 7px;
label {
padding-right: 8px;
}
.el-form-item {
margin-bottom: 15px;
}
}
.emoji-packs-header {
margin: 15px;
}
.emoji-packs-header-button-container {
height: 82px;
flex-direction: column;
.el-button+.el-button {
margin: 7px 0 0 0;
width: fit-content;
}
}
.import-pack-button {
width: 90%;
}
.reload-emoji-button {
width: fit-content;
}
}
</style> </style>

View file

@ -51,6 +51,18 @@ export default {
}, },
loading() { loading() {
return this.settings.loading return this.settings.loading
},
searchQuery() {
return this.$store.state.settings.searchQuery
}
},
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
} }
}, },
methods: { methods: {
@ -76,6 +88,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -18,10 +18,6 @@
<setting :setting-group="assets" :data="assetsData"/> <setting :setting-group="assets" :data="assetsData"/>
</el-form> </el-form>
<el-divider v-if="assets" class="divider thick-line"/> <el-divider v-if="assets" class="divider thick-line"/>
<el-form :model="emojiData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="emoji" :data="emojiData"/>
</el-form>
<el-divider v-if="emoji" class="divider thick-line"/>
<el-form :model="chatData" :label-position="labelPosition" :label-width="labelWidth"> <el-form :model="chatData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="chat" :data="chatData"/> <setting :setting-group="chat" :data="chatData"/>
</el-form> </el-form>
@ -65,12 +61,6 @@ export default {
chatData() { chatData() {
return _.get(this.settings.settings, [':pleroma', ':chat']) || {} return _.get(this.settings.settings, [':pleroma', ':chat']) || {}
}, },
emoji() {
return this.settings.description.find(setting => setting.key === ':emoji')
},
emojiData() {
return _.get(this.settings.settings, [':pleroma', ':emoji']) || {}
},
frontend() { frontend() {
return this.settings.description.find(setting => setting.key === ':frontend_configurations') return this.settings.description.find(setting => setting.key === ':frontend_configurations')
}, },
@ -122,6 +112,9 @@ export default {
preloadData() { preloadData() {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Preload']) || {} return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Preload']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
staticFe() { staticFe() {
return this.settings.description.find(setting => setting.key === ':static_fe') return this.settings.description.find(setting => setting.key === ':static_fe')
}, },
@ -129,6 +122,15 @@ export default {
return _.get(this.settings.settings, [':pleroma', ':static_fe']) || {} return _.get(this.settings.settings, [':pleroma', ':static_fe']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -146,6 +148,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -51,6 +51,18 @@ export default {
}, },
loading() { loading() {
return this.settings.loading return this.settings.loading
},
searchQuery() {
return this.$store.state.settings.searchQuery
}
},
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
} }
}, },
methods: { methods: {
@ -70,6 +82,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -76,6 +76,9 @@ export default {
loading() { loading() {
return this.settings.loading return this.settings.loading
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
webCacheTtl() { webCacheTtl() {
return this.settings.description.find(setting => setting.key === ':web_cache_ttl') return this.settings.description.find(setting => setting.key === ':web_cache_ttl')
}, },
@ -83,6 +86,15 @@ export default {
return _.get(this.settings.settings, [':pleroma', ':web_cache_ttl']) || {} return _.get(this.settings.settings, [':pleroma', ':web_cache_ttl']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -100,6 +112,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -394,6 +394,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -146,6 +146,9 @@ export default {
restrictUnauthenticatedData() { restrictUnauthenticatedData() {
return _.get(this.settings.settings, [':pleroma', ':restrict_unauthenticated']) || {} return _.get(this.settings.settings, [':pleroma', ':restrict_unauthenticated']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
scheduledActivity() { scheduledActivity() {
return this.$store.state.settings.description.find(setting => setting.key === 'Pleroma.ScheduledActivity') return this.$store.state.settings.description.find(setting => setting.key === 'Pleroma.ScheduledActivity')
}, },
@ -172,6 +175,14 @@ export default {
} }
}, },
async mounted() { async mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
await this.$store.dispatch('FetchInstanceDocument', 'instance-panel') await this.$store.dispatch('FetchInstanceDocument', 'instance-panel')
}, },
methods: { methods: {
@ -198,6 +209,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -96,6 +96,9 @@ export default {
poolsData() { poolsData() {
return _.get(this.settings.settings, [':pleroma', ':pools']) || {} return _.get(this.settings.settings, [':pleroma', ':pools']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
workers() { workers() {
return this.settings.description.find(setting => setting.key === ':workers') return this.settings.description.find(setting => setting.key === ':workers')
}, },
@ -103,6 +106,15 @@ export default {
return _.get(this.settings.settings, [':pleroma', ':workers']) || {} return _.get(this.settings.settings, [':pleroma', ':workers']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -120,6 +132,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -51,6 +51,18 @@ export default {
}, },
loading() { loading() {
return this.settings.loading return this.settings.loading
},
searchQuery() {
return this.$store.state.settings.searchQuery
}
},
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
} }
}, },
methods: { methods: {
@ -70,6 +82,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -76,6 +76,9 @@ export default {
loggerData() { loggerData() {
return _.get(this.settings.settings, [':logger', ':backends']) || {} return _.get(this.settings.settings, [':logger', ':backends']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
quack() { quack() {
return this.settings.description.find(setting => setting.group === ':quack') return this.settings.description.find(setting => setting.group === ':quack')
}, },
@ -83,6 +86,15 @@ export default {
return _.get(this.settings.settings, [':quack']) || {} return _.get(this.settings.settings, [':quack']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -100,6 +112,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -51,6 +51,18 @@ export default {
}, },
mrfSettings() { mrfSettings() {
return this.settings.description.filter(el => el.tab === 'mrf') return this.settings.description.filter(el => el.tab === 'mrf')
},
searchQuery() {
return this.$store.state.settings.searchQuery
}
},
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
} }
}, },
methods: { methods: {
@ -83,6 +95,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -82,6 +82,9 @@ export default {
newUsersDigestEmailData() { newUsersDigestEmailData() {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Emails.NewUsersDigestEmail']) || {} return _.get(this.settings.settings, [':pleroma', 'Pleroma.Emails.NewUsersDigestEmail']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
swoosh() { swoosh() {
return this.settings.description.find(setting => setting.group === ':swoosh') return this.settings.description.find(setting => setting.group === ':swoosh')
}, },
@ -95,6 +98,15 @@ export default {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Emails.UserEmail']) || {} return _.get(this.settings.settings, [':pleroma', 'Pleroma.Emails.UserEmail']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -112,6 +124,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -76,6 +76,9 @@ export default {
mediaProxyData() { mediaProxyData() {
return _.get(this.settings.settings, [':pleroma', ':media_proxy']) || {} return _.get(this.settings.settings, [':pleroma', ':media_proxy']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
scriptInvalidation() { scriptInvalidation() {
return this.settings.description.find(setting => setting.key === 'Pleroma.Web.MediaProxy.Invalidation.Script') return this.settings.description.find(setting => setting.key === 'Pleroma.Web.MediaProxy.Invalidation.Script')
}, },
@ -83,6 +86,15 @@ export default {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.MediaProxy.Invalidation.Script']) || {} return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.MediaProxy.Invalidation.Script']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -100,6 +112,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -56,6 +56,9 @@ export default {
metadataData() { metadataData() {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Metadata']) || {} return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Metadata']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
richMedia() { richMedia() {
return this.settings.description.find(setting => setting.key === ':rich_media') return this.settings.description.find(setting => setting.key === ':rich_media')
}, },
@ -63,6 +66,15 @@ export default {
return _.get(this.settings.settings, [':pleroma', ':rich_media']) || {} return _.get(this.settings.settings, [':pleroma', ':rich_media']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -80,6 +92,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -110,6 +110,9 @@ export default {
remoteIpData() { remoteIpData() {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Plugs.RemoteIp']) || {} return _.get(this.settings.settings, [':pleroma', 'Pleroma.Web.Plugs.RemoteIp']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
termsOfServicesContent: { termsOfServicesContent: {
get() { get() {
return this.$store.state.settings.termsOfServices return this.$store.state.settings.termsOfServices
@ -120,6 +123,14 @@ export default {
} }
}, },
async mounted() { async mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
await this.$store.dispatch('FetchInstanceDocument', 'terms-of-service') await this.$store.dispatch('FetchInstanceDocument', 'terms-of-service')
}, },
methods: { methods: {
@ -146,6 +157,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -51,6 +51,18 @@ export default {
}, },
loading() { loading() {
return this.$store.state.settings.loading return this.$store.state.settings.loading
},
searchQuery() {
return this.$store.state.settings.searchQuery
}
},
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
} }
}, },
methods: { methods: {
@ -70,6 +82,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -179,6 +179,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -72,6 +72,9 @@ export default {
s3Data() { s3Data() {
return _.get(this.settings.settings, [':ex_aws', ':s3']) || {} return _.get(this.settings.settings, [':ex_aws', ':s3']) || {}
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
showUploadersS3() { showUploadersS3() {
const uploader = _.get(this.settings.settings, [':pleroma', 'Pleroma.Upload', ':uploader']) const uploader = _.get(this.settings.settings, [':pleroma', 'Pleroma.Upload', ':uploader'])
return uploader === 'Pleroma.Uploaders.S3' return uploader === 'Pleroma.Uploaders.S3'
@ -111,6 +114,15 @@ export default {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Upload.Filter.AnonymizeFilename']) || {} return _.get(this.settings.settings, [':pleroma', 'Pleroma.Upload.Filter.AnonymizeFilename']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -128,6 +140,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -46,6 +46,9 @@ export default {
loading() { loading() {
return this.settings.loading return this.settings.loading
}, },
searchQuery() {
return this.$store.state.settings.searchQuery
},
vapidDetails() { vapidDetails() {
return this.settings.description.find(setting => setting.key === ':vapid_details') return this.settings.description.find(setting => setting.key === ':vapid_details')
}, },
@ -53,6 +56,15 @@ export default {
return _.get(this.settings.settings, [':web_push_encryption', ':vapid_details']) || {} return _.get(this.settings.settings, [':web_push_encryption', ':vapid_details']) || {}
} }
}, },
mounted() {
if (this.searchQuery.length > 0) {
const selectedSetting = document.querySelector(`[data-search="${this.searchQuery}"]`)
if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.$store.dispatch('SetSearchQuery', '')
}
},
methods: { methods: {
async onSubmit() { async onSubmit() {
try { try {
@ -70,6 +82,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../styles/main'; @import '../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -1,6 +1,7 @@
export { default as ActivityPub } from './ActivityPub' export { default as ActivityPub } from './ActivityPub'
export { default as Authentication } from './Authentication' export { default as Authentication } from './Authentication'
export { default as Captcha } from './Captcha' export { default as Captcha } from './Captcha'
export { default as Emoji } from './Emoji'
export { default as Esshd } from './Esshd' export { default as Esshd } from './Esshd'
export { default as Frontend } from './Frontend' export { default as Frontend } from './Frontend'
export { default as Gopher } from './Gopher' export { default as Gopher } from './Gopher'
@ -15,6 +16,5 @@ export { default as Metadata } from './Metadata'
export { default as Mrf } from './MRF' export { default as Mrf } from './MRF'
export { default as Other } from './Other' export { default as Other } from './Other'
export { default as RateLimiters } from './RateLimiters' export { default as RateLimiters } from './RateLimiters'
export { default as Relays } from './Relays'
export { default as Upload } from './Upload' export { default as Upload } from './Upload'
export { default as WebPush } from './WebPush' export { default as WebPush } from './WebPush'

View file

@ -115,6 +115,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -192,6 +192,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -202,6 +202,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include tiptap @include tiptap
</style> </style>

View file

@ -103,6 +103,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -124,7 +124,7 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings; @include settings;
.image-upload-area { .image-upload-area {

View file

@ -103,6 +103,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -99,6 +99,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -77,6 +77,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -148,6 +148,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -69,6 +69,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -110,6 +110,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -93,6 +93,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -62,6 +62,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss'> <style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main'; @import '../../../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -16,9 +16,13 @@ export const tabs = description => {
label: 'settings.captcha', label: 'settings.captcha',
settings: ['Pleroma.Captcha', 'Pleroma.Captcha.Kocaptcha'] settings: ['Pleroma.Captcha', 'Pleroma.Captcha.Kocaptcha']
}, },
'emoji': {
label: 'settings.emoji',
settings: [':emoji']
},
'frontend': { 'frontend': {
label: 'settings.frontend', label: 'settings.frontend',
settings: [':assets', ':chat', ':frontends', ':emoji', ':frontend_configurations', ':markup', ':static_fe'] settings: [':assets', ':chat', ':frontends', ':emoji', ':frontend_configurations', ':markup', ':static_fe', 'Pleroma.Web.Preload']
}, },
'gopher': { 'gopher': {
label: 'settings.gopher', label: 'settings.gopher',
@ -64,10 +68,6 @@ export const tabs = description => {
label: 'settings.rateLimiters', label: 'settings.rateLimiters',
settings: [':rate_limit'] settings: [':rate_limit']
}, },
'relays': {
label: 'settings.relays',
settings: ['relays']
},
'web-push': { 'web-push': {
label: 'settings.webPush', label: 'settings.webPush',
settings: [':vapid_details'] settings: [':vapid_details']

View file

@ -4,7 +4,7 @@
<reboot-button/> <reboot-button/>
</div> </div>
<div v-if="isDesktop"> <div v-if="isDesktop">
<div :class="isSidebarOpen" class="settings-header-container"> <div :class="isSidebarOpen">
<h1 class="settings-header">{{ $t('settings.settings') }}</h1> <h1 class="settings-header">{{ $t('settings.settings') }}</h1>
<div class="docs-search-container"> <div class="docs-search-container">
<el-link <el-link
@ -29,31 +29,11 @@
@select="handleSearchSelect"/> @select="handleSearchSelect"/>
</div> </div>
</div> </div>
<el-tabs v-model="activeTab" tab-position="left"> <component :is="componentName"/>
<el-tab-pane
v-for="(value, componentName) in tabs"
:label="$t(value.label)"
:disabled="configDisabled || settingsCantBeChanged(value.settings)"
:key="componentName"
:name="componentName"
lazy>
<component :is="componentName"/>
</el-tab-pane>
</el-tabs>
</div> </div>
<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>
</div>
<div class="nav-container">
<el-select v-model="activeTab" class="settings-menu" placeholder="Select">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="configDisabled"/>
</el-select>
<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/"
@ -66,38 +46,29 @@
</el-button> </el-button>
</el-link> </el-link>
</div> </div>
<div class="settings-search-input-container"/> <div class="settings-search-container">
<activity-pub v-if="activeTab === 'activityPub'"/> <el-autocomplete
<authentication v-if="activeTab === 'auth'"/> v-model="searchQuery"
<link-formatter v-if="activeTab === 'linkFormatter'"/> :fetch-suggestions="querySearch"
<esshd v-if="activeTab === 'esshd'"/> :trigger-on-focus="false"
<captcha v-if="activeTab === 'captcha'"/> clearable
<frontend v-if="activeTab === 'frontend'"/> placeholder="Search"
<gopher v-if="activeTab === 'gopher'"/> prefix-icon="el-icon-search"
<http v-if="activeTab === 'http'"/> class="settings-search-input"
<instance v-if="activeTab === 'instance'"/> @select="handleSearchSelect"/>
<job-queue v-if="activeTab === 'jobQueue'"/> </div>
<logger v-if="activeTab === 'logger'"/> <component :is="componentName"/>
<mailer v-if="activeTab === 'mailer'"/>
<media-proxy v-if="activeTab === 'mediaProxy'"/>
<metadata v-if="activeTab === 'metadata'"/>
<mrf v-if="activeTab === 'mrf'"/>
<rate-limiters v-if="activeTab === 'rateLimiters'"/>
<relays v-if="activeTab === 'relays'"/>
<web-push v-if="activeTab === 'webPush'"/>
<upload v-if="activeTab === 'upload'"/>
<other v-if="activeTab === 'other'"/>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import i18n from '@/lang'
import { tabs } from './components/tabs' import { tabs } from './components/tabs'
import { import {
ActivityPub, ActivityPub,
Authentication, Authentication,
Captcha, Captcha,
Emoji,
Esshd, Esshd,
Frontend, Frontend,
Gopher, Gopher,
@ -112,7 +83,6 @@ import {
Mrf, Mrf,
Other, Other,
RateLimiters, RateLimiters,
Relays,
Upload, Upload,
WebPush WebPush
} from './components' } from './components'
@ -123,6 +93,7 @@ export default {
ActivityPub, ActivityPub,
Authentication, Authentication,
Captcha, Captcha,
Emoji,
Esshd, Esshd,
Frontend, Frontend,
Gopher, Gopher,
@ -137,46 +108,18 @@ export default {
Mrf, Mrf,
Other, Other,
RateLimiters, RateLimiters,
Relays,
RebootButton, RebootButton,
Upload, Upload,
WebPush WebPush
}, },
data() { data() {
return { return {
options: [
{ value: 'activityPub', label: i18n.t('settings.activityPub') },
{ value: 'auth', label: i18n.t('settings.auth') },
{ value: 'linkFormatter', label: i18n.t('settings.linkFormatter') },
{ value: 'esshd', label: i18n.t('settings.esshd') },
{ value: 'captcha', label: i18n.t('settings.captcha') },
{ value: 'frontend', label: i18n.t('settings.frontend') },
{ value: 'gopher', label: i18n.t('settings.gopher') },
{ value: 'http', label: i18n.t('settings.http') },
{ value: 'instance', label: i18n.t('settings.instance') },
{ value: 'jobQueue', label: i18n.t('settings.jobQueue') },
{ value: 'logger', label: i18n.t('settings.logger') },
{ value: 'mailer', label: i18n.t('settings.mailer') },
{ value: 'mediaProxy', label: i18n.t('settings.mediaProxy') },
{ value: 'metadata', label: i18n.t('settings.metadata') },
{ value: 'mrf', label: i18n.t('settings.mrf') },
{ value: 'rateLimiters', label: i18n.t('settings.rateLimiters') },
{ value: 'relays', label: i18n.t('settings.relays') },
{ value: 'webPush', label: i18n.t('settings.webPush') },
{ value: 'upload', label: i18n.t('settings.upload') },
{ value: 'other', label: i18n.t('settings.other') }
],
searchQuery: '' searchQuery: ''
} }
}, },
computed: { computed: {
activeTab: { componentName() {
get() { return this.$route.path.split('/settings/').pop()
return this.$store.state.settings.activeTab
},
set(tab) {
this.$store.dispatch('SetActiveTab', tab)
}
}, },
configDisabled() { configDisabled() {
return this.$store.state.settings.configDisabled return this.$store.state.settings.configDisabled
@ -209,12 +152,19 @@ export default {
this.$store.dispatch('FetchSettings') this.$store.dispatch('FetchSettings')
}, },
methods: { methods: {
async handleSearchSelect(selectedValue) { handleSearchSelect(selectedValue) {
this.$store.dispatch('SetSearchQuery', selectedValue.key)
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)
}) })
await this.$store.dispatch('SetActiveTab', tab) if (this.$router.currentRoute.path === `/settings/${tab}`) {
const selectedSetting = document.querySelector(`[data-search="${selectedValue.key}"]`) this.scrollTo(selectedValue.key)
} else if (tab) {
this.$router.push({ path: `/settings/${tab}` })
}
},
scrollTo(searchQuery) {
const selectedSetting = document.querySelector(`[data-search="${searchQuery}"]`)
if (selectedSetting) { if (selectedSetting) {
selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' }) selectedSetting.scrollIntoView({ block: 'start', behavior: 'smooth' })
} }
@ -232,8 +182,6 @@ export default {
return this.$store.state.settings.description.findIndex(el => el.group === setting) !== -1 return this.$store.state.settings.description.findIndex(el => el.group === setting) !== -1
} else if (setting === 'Pleroma.Web.Auth.Authenticator' || setting === ':admin_token') { } else if (setting === 'Pleroma.Web.Auth.Authenticator' || setting === ':admin_token') {
return this.$store.state.settings.description.findIndex(el => el.children[0].key === setting) !== -1 return this.$store.state.settings.description.findIndex(el => el.children[0].key === setting) !== -1
} else if (setting === 'relays') {
return [setting]
} else { } else {
return this.$store.state.settings.description.findIndex(el => el.key === setting) !== -1 return this.$store.state.settings.description.findIndex(el => el.key === setting) !== -1
} }
@ -245,6 +193,6 @@ export default {
</script> </script>
<style rel='stylesheet/scss' lang='scss' scoped> <style rel='stylesheet/scss' lang='scss' scoped>
@import './styles/main'; @import '../styles/settings';
@include settings @include settings
</style> </style>

View file

@ -0,0 +1,31 @@
@mixin relays {
.follow-relay {
width: 350px;
margin-right: 7px;
}
.relays-container {
margin: 0 15px;
}
.relays-header-container {
display: flex;
align-items: center;
justify-content: space-between;
}
@media only screen and (max-width:480px) {
.follow-relay {
width: 75%;
margin-right: 5px;
input {
width: 100%;
}
}
.follow-relay-container {
display: flex;
justify-content: space-between;
margin: 0 5px;
}
.relays-container {
margin: 0 10px;
}
}
}

View file

@ -30,7 +30,8 @@
height: 2px; height: 2px;
} }
.docs-search-container { .docs-search-container {
float: right; display: flex;
justify-content: flex-end;
margin-right: 30px; margin-right: 30px;
} }
.editable-keyword-container { .editable-keyword-container {
@ -68,10 +69,6 @@
padding: 2px 3px; padding: 2px 3px;
} }
} }
.follow-relay {
width: 350px;
margin-right: 7px;
}
.form-container { .form-container {
margin-bottom: 80px; margin-bottom: 80px;
} }
@ -271,9 +268,6 @@
right: 0; right: 0;
z-index: 2000; z-index: 2000;
} }
.relays-container {
margin: 0 15px;
}
.replacement-input { .replacement-input {
width: 80%; width: 80%;
margin-left: 8px; margin-left: 8px;
@ -325,9 +319,6 @@
.header-sidebar-closed { .header-sidebar-closed {
max-width: 1728px; max-width: 1728px;
} }
.settings-header-container {
height: 87px;
}
.settings-search-input { .settings-search-input {
width: 350px; width: 350px;
margin-left: 5px; margin-left: 5px;
@ -457,18 +448,6 @@
.divider .thick-line { .divider .thick-line {
height: 2px; height: 2px;
} }
.follow-relay {
width: 75%;
margin-right: 5px;
input {
width: 100%;
}
}
.follow-relay-container {
display: flex;
justify-content: space-between;
margin: 0 5px;
}
.frontend-container { .frontend-container {
margin: 0 15px 10px 15px; margin: 0 15px 10px 15px;
.description-container { .description-container {
@ -515,13 +494,6 @@
.limit-input { .limit-input {
width: 45%; width: 45%;
} }
.nav-container {
display: flex;
height: 36px;
justify-content: space-between;
align-items: center;
margin: 15px;
}
.proxy-url-input { .proxy-url-input {
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
@ -567,19 +539,9 @@
display: inline-block; display: inline-block;
margin: 10px 15px 15px 15px; margin: 10px 15px 15px 15px;
} }
.docs-search-container {
float: right;
}
.settings-search-input { .settings-search-input {
width: 100%; margin: 0 15px 25px 15px;
margin-left: 0; width: stretch;
}
.settings-search-input-container {
margin: 0 15px 15px 15px;
}
.settings-menu {
width: 163px;
margin-right: 5px;
} }
.socks5-checkbox-container { .socks5-checkbox-container {
width: 100%; width: 100%;
@ -660,16 +622,15 @@
width: 40%; width: 40%;
margin-right: 4px margin-right: 4px
} }
.relays-container {
margin: 0 10px;
}
.replacement-input { .replacement-input {
width: 60%; width: 60%;
margin-left: 4px; margin-left: 4px;
margin-right: 5px margin-right: 5px
} }
.settings-header-container { .settings-header-container {
height: 45px; display: flex;
justify-content: space-between;
margin-right: 15px;
} }
.value-input { .value-input {
width: 60%; width: 60%;
@ -677,6 +638,7 @@
margin-right: 8px margin-right: 8px
} }
} }
@media only screen and (max-width:818px) and (min-width: 481px) { @media only screen and (max-width:818px) and (min-width: 481px) {
.delete-setting-button { .delete-setting-button {
margin: 4px 0 0 10px; margin: 4px 0 0 10px;
@ -708,13 +670,6 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
.nav-container {
display: flex;
height: 36px;
justify-content: space-between;
align-items: center;
margin: 15px 30px 15px 15px;
}
.rate-limit-content { .rate-limit-content {
width: 65%; width: 65%;
} }
@ -725,7 +680,14 @@
float: right; float: right;
} }
.settings-header-container { .settings-header-container {
height: 36px; display: flex;
justify-content: space-between;
margin-right: 15px;
}
.settings-search-container {
display: flex;
justify-content: flex-end;
margin-right: 15px;
} }
.settings-search-input { .settings-search-input {
width: 250px; width: 250px;
@ -898,3 +860,122 @@
} }
} }
} }
@mixin emoji {
.create-pack {
display: flex;
justify-content: space-between
}
.create-pack-button {
margin-left: 10px;
}
.emoji-header-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 15px 22px 15px;
}
.emoji-name-warning {
color: #666666;
font-size: 13px;
line-height: 22px;
margin: 5px 0 0 0;
overflow-wrap: break-word;
overflow: hidden;
text-overflow: ellipsis;
}
.emoji-packs-header-button-container {
display: flex;
}
.emoji-packs-form {
margin-top: 15px;
}
.emoji-packs-header {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 15px 15px 15px;
}
.emoji-packs-tabs {
margin: 0 15px 15px 15px;
}
.import-pack-button {
margin-left: 10px;
width: 30%;
max-width: 700px;
}
h1 {
margin: 0;
}
.line {
width: 100%;
height: 0;
border: 1px solid #eee;
margin-bottom: 22px;
}
.pagination {
margin: 25px 0;
text-align: center;
}
.reboot-button {
padding: 10px;
margin: 0;
width: 145px;
}
@media only screen and (min-width: 1824px) {
.emoji-packs {
max-width: 1824px;
margin: auto;
}
}
@media only screen and (max-width:480px) {
.create-pack {
height: 82px;
flex-direction: column;
}
.create-pack-button {
margin-left: 0;
}
.divider {
margin: 15px 0;
}
.el-message {
min-width: 80%;
}
.el-message-box {
width: 80%;
}
.emoji-header-container {
flex-direction: column;
align-items: flex-start;
}
.emoji-packs-form {
margin: 0 7px;
label {
padding-right: 8px;
}
.el-form-item {
margin-bottom: 15px;
}
}
.emoji-packs-header {
margin: 15px;
}
.emoji-packs-header-button-container {
height: 82px;
flex-direction: column;
.el-button+.el-button {
margin: 7px 0 0 0;
width: fit-content;
}
}
.import-pack-button {
width: 90%;
}
.reload-emoji-button {
width: fit-content;
}
}
}

View file

@ -173,27 +173,29 @@ describe('Form search object', () => {
label: "Admin token" } label: "Admin token" }
] ]
}] }]
const expected = [{ const expected = [
label: "Admin token", {
key: ":admin_token", label: "Admin token",
groupKey: ":pleroma", key: ":admin_token",
groupLabel: "Pleroma", groupKey: ":pleroma",
search: [":admin_token", "admin token", "token"] groupLabel: "Pleroma",
}, search: [":admin_token", "admin token", "token"]
{ },
groupKey: ':instance_panel', {
groupLabel: 'Instance Panel', groupKey: ':instance_panel',
key: ':instance_panel', groupLabel: 'Instance Panel',
label: 'Instance Panel', key: ':instance_panel',
search: ['Instance Panel', ':instance_panel'] label: 'Instance Panel',
}, search: ['Instance Panel', ':instance_panel']
{ },
groupKey: ':terms_of_services', {
groupLabel: 'Terms of Services', groupKey: ':terms_of_services',
key: ':terms_of_services', groupLabel: 'Terms of Services',
label: 'Terms of Services', key: ':terms_of_services',
search: ['Terms of Services', ':terms_of_services'] label: 'Terms of Services',
}] search: ['Terms of Services', ':terms_of_services']
}
]
expect(_.isEqual(formSearchObject(description), expected)).toBeTruthy() expect(_.isEqual(formSearchObject(description), expected)).toBeTruthy()
}) })
@ -269,7 +271,8 @@ describe('Form search object', () => {
key: ':instance_panel', key: ':instance_panel',
label: 'Instance Panel', label: 'Instance Panel',
search: ['Instance Panel', ':instance_panel'] search: ['Instance Panel', ':instance_panel']
}, { },
{
groupKey: ':terms_of_services', groupKey: ':terms_of_services',
groupLabel: 'Terms of Services', groupLabel: 'Terms of Services',
key: ':terms_of_services', key: ':terms_of_services',

View file

@ -7,6 +7,7 @@ import app from '@/store/modules/app'
import settings from '@/store/modules/settings' import settings from '@/store/modules/settings'
import user from '@/store/modules/user' import user from '@/store/modules/user'
import getters from '@/store/getters' import getters from '@/store/getters'
import _ from 'lodash'
config.mocks["$t"] = () => {} config.mocks["$t"] = () => {}
@ -22,6 +23,8 @@ describe('Settings search', () => {
let store let store
let actions let actions
let appActions let appActions
let $route
let $router
beforeEach(() => { beforeEach(() => {
appActions = { ...app.actions, NeedReboot: jest.fn() } appActions = { ...app.actions, NeedReboot: jest.fn() }
@ -34,11 +37,17 @@ describe('Settings search', () => {
}, },
getters getters
}) })
$route = { path: '/settings/path' }
$router = { push: jest.fn(), currentRoute: {} }
}) })
it('shows search input', async (done) => { it('shows search input', async (done) => {
const wrapper = mount(Settings, { const wrapper = mount(Settings, {
store, store,
mocks: {
$route,
$router
},
localVue localVue
}) })
@ -47,22 +56,31 @@ describe('Settings search', () => {
expect(searchInput.exists()).toBe(true) expect(searchInput.exists()).toBe(true)
done() done()
}) })
it('changes tab when search value was selected', async (done) => { it('changes tab when search value was selected', async (done) => {
const wrapper = mount(Settings, { const wrapper = mount(Settings, {
store, store,
mocks: {
$route,
$router
},
localVue localVue
}) })
wrapper.vm.handleSearchSelect({ group: 'Pleroma.Upload', key: 'Pleroma.Upload' }) wrapper.vm.handleSearchSelect({ group: 'Pleroma.Upload', key: 'Pleroma.Upload' })
expect(store.state.settings.activeTab).toBe('upload') expect(store.state.settings.searchQuery).toBe('Pleroma.Upload')
expect($router.push).toHaveBeenCalledWith({ path: '/settings/upload' })
wrapper.vm.handleSearchSelect({ group: ':swoosh', key: ':serve_mailbox' }) wrapper.vm.handleSearchSelect({ group: ':swoosh', key: ':serve_mailbox' })
expect(store.state.settings.activeTab).toBe('mailer') expect(store.state.settings.searchQuery).toBe(':serve_mailbox')
expect($router.push).toHaveBeenCalledWith({ path: '/settings/mailer' })
wrapper.vm.handleSearchSelect({ group: ':pleroma', key: ':admin_token' }) wrapper.vm.handleSearchSelect({ group: ':pleroma', key: ':admin_token' })
expect(store.state.settings.activeTab).toBe('instance') expect(store.state.settings.searchQuery).toBe(':admin_token')
expect($router.push).toHaveBeenCalledWith({ path: '/settings/instance' })
wrapper.vm.handleSearchSelect({ group: ':media_proxy', key: ':ssl_options' }) wrapper.vm.handleSearchSelect({ group: ':media_proxy', key: ':ssl_options' })
expect(store.state.settings.activeTab).toBe('media-proxy') expect(store.state.settings.searchQuery).toBe(':ssl_options')
expect($router.push).toHaveBeenCalledWith({ path: '/settings/media-proxy' })
done() done()
}) })

View file

@ -11258,10 +11258,10 @@ vue-loader@15.3.0:
vue-hot-reload-api "^2.3.0" vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0" vue-style-loader "^4.1.0"
vue-router@3.0.2: vue-router@^3.5.1:
version "3.0.2" version "3.5.1"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.2.tgz#dedc67afe6c4e2bc25682c8b1c2a8c0d7c7e56be" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.5.1.tgz#edf3cf4907952d1e0583e079237220c5ff6eb6c9"
integrity sha512-opKtsxjp9eOcFWdp6xLQPLmRGgfM932Tl56U9chYTnoWqKxQ8M20N7AkdEbM5beUh6wICoFGYugAX9vQjyJLFg== integrity sha512-RRQNLT8Mzr8z7eL4p7BtKvRaTSGdCbTy2+Mm5HTJvLGYSSeG9gDzNasJPP/yOYKLy+/cLG/ftrqq5fvkFwBJEw==
vue-splitpane@1.0.2: vue-splitpane@1.0.2:
version "1.0.2" version "1.0.2"