Merge branch 'feature/settings-mobile-ui' into 'develop'

Add mobile interface for settings and other admin-fe tabs

Closes #83, #82, #81, and #80

See merge request pleroma/admin-fe!91
This commit is contained in:
Angelina Filippova 2020-02-16 20:30:04 +00:00
commit 436934109a
38 changed files with 795 additions and 383 deletions

View file

@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Report notes
- Ability to moderate users on the statuses page
- Ability to moderate user on the user's page
- Mobile UI for Settings tab
### Fixed
@ -36,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Reports update (also, now it's optimistic)
- Remove duplicated success message
- Fix styles for Statuses by instance page
- Fix styles for Reports section
## [1.2.0] - 2019-09-27

View file

@ -214,6 +214,7 @@ export default {
<style rel='stylesheet/scss' lang='scss'>
.status-card {
margin-bottom: 10px;
.account {
text-decoration: underline;
line-height: 26px;
@ -254,9 +255,6 @@ export default {
font-size: 15px;
line-height: 26px;
}
.status-card {
margin-bottom: 15px;
}
.status-deleted {
font-style: italic;
margin-top: 3px;

View file

@ -359,7 +359,11 @@ export default {
metadatLowerCase: 'metadata',
files: 'files',
successfullyRemoved: 'Setting removed successfully!',
seeDocs: 'See Documentation'
seeDocs: 'See Documentation',
assets: 'Assets',
emoji: 'Emoji',
markup: 'Markup settings',
corsPlug: 'CORS plug config'
},
invites: {
inviteTokens: 'Invite tokens',

View file

@ -9,7 +9,7 @@
</el-button>
</el-tooltip>
</div>
<div class="line"/>
<el-divider class="divider"/>
<el-form label-width="180px" class="emoji-packs-form">
<el-form-item :label="$t('emoji.localPacks')">
<el-button type="primary" @click="refreshLocalPacks">{{ $t('emoji.refreshLocalPacks') }}</el-button>
@ -30,7 +30,7 @@
<emoji-pack :name="name" :pack="pack" :host="$store.getters.authHost" :is-local="true" />
</el-collapse>
</el-form-item>
<div class="line"/>
<el-divider class="divider"/>
<el-form-item :label="$t('emoji.remotePacks')">
<div class="create-pack">
<el-input
@ -72,7 +72,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '240px'
return this.isMobile ? '120px' : '240px'
},
localPacks() {
return this.$store.state.emojiPacks.localPacks

View file

@ -1,5 +1,5 @@
<template>
<el-timeline class="timeline">
<el-timeline class="reports-timeline">
<el-timeline-item
v-for="groupedReport in groupedReports"
:key="groupedReport.id"
@ -13,7 +13,7 @@
</div>
<div>
<el-dropdown trigger="click">
<el-button plain size="small" icon="el-icon-edit">{{ $t('reports.changeAllReports') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
<el-button plain size="small" icon="el-icon-edit" class="report-actions-button">{{ $t('reports.changeAllReports') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="changeAllReports('resolved', groupedReport.reports)">{{ $t('reports.resolveAll') }}</el-dropdown-item>
<el-dropdown-item @click.native="changeAllReports('open', groupedReport.reports)">{{ $t('reports.reopenAll') }}</el-dropdown-item>
@ -24,7 +24,7 @@
</div>
</div>
<div>
<div class="line"/>
<el-divider class="divider"/>
<span class="report-row-key">{{ $t('reports.account') }}:</span>
<img
:src="groupedReport.account.avatar"
@ -35,7 +35,7 @@
</a>
</div>
<div>
<div class="line"/>
<el-divider class="divider"/>
<span class="report-row-key">{{ $t('reports.actors') }}:</span>
<span v-for="(actor, index) in groupedReport.actors" :key="actor.id">
<a :href="actor.url" target="_blank">
@ -44,9 +44,9 @@
</span>
</div>
<div v-if="groupedReport.status">
<div class="line"/>
<el-divider class="divider"/>
<span class="report-row-key">{{ $t('reports.reportedStatus') }}:</span>
<status :status="groupedReport.status" class="reported-status"/>
<status :status="groupedReport.status" :show-checkbox="false" class="reported-status"/>
</div>
<div v-if="groupedReport.reports">
<el-collapse>
@ -109,11 +109,13 @@ export default {
.el-icon-arrow-right {
margin-right: 6px;
}
.header-container {
display: flex;
justify-content: space-between;
align-items: baseline;
height: 40px;
.grouped-report {
.header-container {
display: flex;
justify-content: space-between;
align-items: baseline;
height: 36px;
}
}
.line {
width: 100%;
@ -128,16 +130,30 @@ export default {
font-size: 14px;
font-weight: 500;
}
.reports-timeline {
margin: 30px 45px 45px 19px;
padding: 0px;
}
.reported-status {
margin-top: 15px;
}
@media
only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px) {
.header-container {
display: flex;
flex-direction: column;
height: 80px;
.grouped-report {
.header-container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
height: auto;
}
.report-actions-button {
margin: 3px 0 6px;
}
.report-title {
margin-bottom: 7px;
}
}
}
</style>

View file

@ -1,22 +1,22 @@
<template>
<div>
<el-timeline class="timeline">
<el-timeline class="reports-timeline">
<el-timeline-item
v-for="report in reports"
:timestamp="parseTimestamp(report.created_at)"
:key="report.id"
placement="top"
class="timeline-item-container">
<el-card>
<el-card class="report">
<div class="header-container">
<div>
<div class="title-container">
<h3 class="report-title">{{ $t('reports.reportOn') }} {{ report.account.display_name }}</h3>
<h5 class="id">{{ $t('reports.id') }}: {{ report.id }}</h5>
</div>
<div>
<el-tag :type="getStateType(report.state)" size="large">{{ capitalizeFirstLetter(report.state) }}</el-tag>
<el-tag :type="getStateType(report.state)" size="large" class="report-tag">{{ capitalizeFirstLetter(report.state) }}</el-tag>
<el-dropdown trigger="click">
<el-button plain size="small" icon="el-icon-edit">{{ $t('reports.changeState') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
<el-button plain size="small" icon="el-icon-edit" class="report-actions-button">{{ $t('reports.changeState') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-if="report.state !== 'resolved'" @click.native="changeReportState('resolved', report.id)">{{ $t('reports.resolve') }}</el-dropdown-item>
<el-dropdown-item v-if="report.state !== 'open'" @click.native="changeReportState('open', report.id)">{{ $t('reports.reopen') }}</el-dropdown-item>
@ -27,7 +27,7 @@
</div>
</div>
<div>
<div class="line"/>
<el-divider class="divider"/>
<span class="report-row-key">{{ $t('reports.account') }}:</span>
<img
:src="report.account.avatar"
@ -38,13 +38,13 @@
</a>
</div>
<div v-if="report.content.length > 0">
<div class="line"/>
<el-divider class="divider"/>
<span class="report-row-key">{{ $t('reports.content') }}:
<span>{{ report.content }}</span>
</span>
</div>
<div>
<div class="line"/>
<div :style="showStatuses(report.statuses) ? '' : 'margin-bottom:15px'">
<el-divider class="divider"/>
<span class="report-row-key">{{ $t('reports.actor') }}:</span>
<img
:src="report.actor.avatar"
@ -54,7 +54,7 @@
<span>{{ report.actor.acct }}</span>
</a>
</div>
<div v-if="report.statuses.length > 0" class="statuses">
<div v-if="showStatuses(report.statuses)" class="statuses">
<el-collapse>
<el-collapse-item :title="getStatusesTitle(report.statuses)">
<div v-for="status in report.statuses" :key="status.id">
@ -153,15 +153,18 @@ export default {
getNotesTitle(notes = []) {
return `Notes: ${notes.length} item(s)`
},
handleNewNote(reportID) {
this.$store.dispatch('CreateReportNote', { content: this.notes[reportID], reportID })
this.notes[reportID] = ''
},
handlePageChange(page) {
this.$store.dispatch('FetchReports', page)
},
parseTimestamp(timestamp) {
return moment(timestamp).format('L HH:mm')
},
handleNewNote(reportID) {
this.$store.dispatch('CreateReportNote', { content: this.notes[reportID], reportID })
this.notes[reportID] = ''
showStatuses(statuses) {
return statuses.length > 0
}
}
}
@ -205,11 +208,13 @@ export default {
margin: 0;
height: 17px;
}
.header-container {
display: flex;
justify-content: space-between;
align-items: baseline;
height: 40px;
.report {
.header-container {
display: flex;
justify-content: space-between;
align-items: baseline;
height: 40px;
}
}
.id {
color: gray;
@ -258,6 +263,10 @@ export default {
margin: 25px 0;
text-align: center;
}
.reports-timeline {
margin: 30px 45px 45px 19px;
padding: 0px;
}
.statuses {
margin-top: 15px;
}
@ -273,15 +282,26 @@ export default {
@media
only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px) {
.timeline-item-container {
.report {
.header-container {
display: flex;
flex-direction: column;
height: 80px;
justify-content: flex-start;
align-items: flex-start;
height: auto;
}
.id {
margin: 6px 0 0 0;
}
.report-actions-button {
margin: 3px 0 6px;
}
.report-tag {
margin: 3px 0 6px;
}
.title-container {
margin-bottom: 7px;
}
}
}
</style>

View file

@ -13,7 +13,7 @@
</a>
</div>
<div>
<el-tag :type="getStateType(report.state)" size="large">{{ capitalizeFirstLetter(report.state) }}</el-tag>
<el-tag :type="getStateType(report.state)" size="large" class="report-tag">{{ capitalizeFirstLetter(report.state) }}</el-tag>
<el-dropdown trigger="click">
<el-button plain size="small" icon="el-icon-edit">{{ $t('reports.changeState') }}<i class="el-icon-arrow-down el-icon--right"/></el-button>
<el-dropdown-menu slot="dropdown">
@ -117,14 +117,12 @@ export default {
.report-header {
display: flex;
flex-direction: column;
height: 80px;
justify-content: flex-start;
align-items: flex-start;
height: auto;
}
.report-actor-container {
margin-bottom: 5px;
}
.report-header {
display: flex;
flex-direction: column;
.report-tag {
margin: 3px 0 6px;
}
}
</style>

View file

@ -8,7 +8,7 @@
{{ $t('reports.reports') }}
<span class="report-count">({{ normalizedReportsCount }})</span>
</h1>
<div class="filter-container">
<div class="reports-filter-container">
<reports-filter v-if="!groupReports"/>
<el-checkbox v-model="groupReports" class="group-reports-checkbox">
Group reports by statuses
@ -70,13 +70,10 @@ export default {
<style rel='stylesheet/scss' lang='scss' scoped>
.reports-container {
.el-timeline {
margin: 45px 45px 45px 19px;
padding: 0px;
}
.filter-container {
.reports-filter-container {
display: flex;
flex-direction: column;
align-items: flex-start;
margin: 22px 15px 22px 15px;
padding-bottom: 0
}
@ -102,8 +99,8 @@ only screen and (max-width: 760px),
h1 {
margin: 7px 10px 15px 10px;
}
.filter-container {
margin: 0 10px
.reports-filter-container {
margin: 0 10px;
}
}
#app > div > div.main-container > section > div > div.block > ul {

View file

@ -3,7 +3,7 @@
<el-form ref="activitypubData" :model="activitypubData" :label-width="labelWidth">
<setting :setting-group="activitypub" :data="activitypubData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="userData" :model="userData" :label-width="labelWidth">
<setting :setting-group="user" :data="userData"/>
</el-form>
@ -36,7 +36,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.$store.state.settings.loading

View file

@ -3,15 +3,15 @@
<el-form ref="pleromaAuthenticatorData" :model="pleromaAuthenticatorData" :label-width="labelWidth">
<setting :setting-group="pleromaAuthenticator" :data="pleromaAuthenticatorData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="authData" :model="authData" :label-width="labelWidth">
<setting :setting-group="auth" :data="authData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="ldapData" :model="ldapData" :label-width="labelWidth">
<setting :setting-group="ldap" :data="ldapData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="oauth2" :model="oauth2Data" :label-width="labelWidth">
<setting :setting-group="oauth2" :data="oauth2Data"/>
</el-form>
@ -44,7 +44,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
ldap() {
return this.settings.description.find(setting => setting.key === ':ldap')

View file

@ -32,7 +32,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -3,7 +3,7 @@
<el-form ref="captchaData" :model="captchaData" :label-width="labelWidth">
<setting :setting-group="captcha" :data="captchaData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="kocaptchaData" :model="kocaptchaData" :label-width="labelWidth">
<setting :setting-group="kocaptcha" :data="kocaptchaData"/>
</el-form>
@ -42,7 +42,7 @@ export default {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.Captcha.Kocaptcha']) || {}
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -32,7 +32,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -4,21 +4,27 @@
<setting :setting-group="frontend" :data="frontendData"/>
</el-form>
<el-form ref="assetsData" :model="assetsData" :label-width="labelWidth">
<el-form-item label="Assets:"/>
<el-form-item class="grouped-settings-header">
<span class="label-font">{{ $t('settings.assets') }}</span>
</el-form-item>
<setting :setting-group="assets" :data="assetsData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="emojiData" :model="emojiData" :label-width="labelWidth">
<el-form-item label="Emoji:"/>
<el-form-item class="grouped-settings-header">
<span class="label-font">{{ $t('settings.emoji') }}</span>
</el-form-item>
<setting :setting-group="emoji" :data="emojiData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="chatData" :model="chatData" :label-width="labelWidth">
<setting :setting-group="chat" :data="chatData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="markupData" :model="markupData" :label-width="labelWidth">
<el-form-item label="Markup settings:"/>
<el-form-item class="grouped-settings-header">
<span class="label-font">{{ $t('settings.markup') }}</span>
</el-form-item>
<setting :setting-group="markup" :data="markupData"/>
</el-form>
<div class="submit-button-container">
@ -74,7 +80,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -32,7 +32,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -4,18 +4,20 @@
<setting :setting-group="http" :data="httpData"/>
</el-form>
<el-form ref="corsPlugData" :model="corsPlugData" :label-width="labelWidth">
<el-form-item label="Cors plug config:"/>
<el-form-item class="grouped-settings-header">
<span class="label-font">{{ $t('settings.corsPlug') }}</span>
</el-form-item>
<setting :setting-group="corsPlug" :data="corsPlugData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="httpSignatures" :model="httpSignaturesData" :label-width="labelWidth">
<setting :setting-group="httpSignatures" :data="httpSignaturesData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="httpSecurityData" :model="httpSecurityData" :label-width="labelWidth">
<setting :setting-group="httpSecurity" :data="httpSecurityData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="webCacheTtl" :model="webCacheTtlData" :label-width="labelWidth">
<setting :setting-group="webCacheTtl" :data="webCacheTtlData"/>
</el-form>
@ -66,7 +68,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -1,88 +1,107 @@
<template>
<el-form-item :label-width="customLabelWidth" :class="labelClass">
<span slot="label">
{{ setting.label }}
<el-tooltip v-if="canBeDeleted" :content="$t('settings.removeFromDB')" placement="bottom-end">
<el-button icon="el-icon-delete" circle size="mini" style="margin-left:5px" @click="removeSetting"/>
</el-tooltip>
</span>
<el-input
v-if="setting.type === 'string' || (setting.type.includes('string') && setting.type.includes('atom'))"
:value="inputValue"
:placeholder="setting.suggestions ? setting.suggestions[0] : null"
@input="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-switch
v-if="setting.type === 'boolean'"
:value="inputValue"
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-input-number
v-if="setting.type === 'integer'"
:value="inputValue === null ? 0 : inputValue"
:placeholder="setting.suggestions ? setting.suggestions[0].toString() : null"
:min="0"
size="large"
class="top-margin"
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-select
v-if="setting.type === 'module' || (setting.type.includes('atom') && setting.type.includes('dropdown'))"
:value="inputValue"
clearable
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)">
<el-option
v-for="(option, index) in setting.suggestions"
:value="option"
:key="index"/>
</el-select>
<el-select
v-if="renderMultipleSelect(setting.type)"
:value="setting.key === ':rewrite_policy' ? rewritePolicyValue : inputValue"
multiple
filterable
allow-create
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)">
<el-option v-for="(option, index) in setting.suggestions" :key="index" :value="option"/>
</el-select>
<el-input
v-if="setting.key === ':ip'"
:value="inputValue"
placeholder="xxx.xxx.xxx.xx"
@input="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-input
v-if="setting.type === 'atom'"
:value="inputValue"
:placeholder="setting.suggestions[0] ? setting.suggestions[0].substr(1) : ''"
@input="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)">
<template slot="prepend">:</template>
</el-input>
<div v-if="setting.type === 'keyword'">
<div v-for="subSetting in setting.children" :key="subSetting.key">
<div class="input-container">
<div v-if="setting.type === 'keyword'" class="keyword-container">
<el-form-item :label-width="customLabelWidth" :class="labelClass" :style="`margin-left:${margin}px;margin-bottom:0`" >
<span slot="label">
{{ setting.label }}
<el-tooltip v-if="canBeDeleted && isDesktop" :content="$t('settings.removeFromDB')" placement="bottom-end">
<el-button icon="el-icon-delete" circle size="mini" class="delete-setting-button" @click="removeSetting"/>
</el-tooltip>
</span>
</el-form-item>
<el-form-item v-for="subSetting in setting.children" :key="subSetting.key">
<inputs
:setting-group="settingGroup"
:setting-parent="[...settingParent, subSetting]"
:setting="subSetting"
:data="data[setting.key]"
:custom-label-width="'140px'"
:label-class="'center-label'"
:input-class="'keyword-inner-input'"
:custom-label-width="isDesktop ? '120px' : '100px'"
:label-class="subSetting.type === 'keyword' ? 'center-label' : ''"
:margin="isDesktop ? margin + 15 : margin + 8"
:nested="true"/>
</div>
</el-form-item>
</div>
<!-- special inputs -->
<auto-linker-input v-if="settingGroup.group === ':auto_linker'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<mascots-input v-if="setting.key === ':mascots'" :data="keywordData" :setting-group="settingGroup" :setting="setting"/>
<editable-keyword-input v-if="editableKeyword(setting.key, setting.type)" :data="keywordData" :setting-group="settingGroup" :setting="setting"/>
<icons-input v-if="setting.key === ':icons'" :data="iconsData" :setting-group="settingGroup" :setting="setting"/>
<proxy-url-input v-if="setting.key === ':proxy_url'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting" :parents="settingParent"/>
<multiple-select v-if="setting.key === ':backends' || setting.key === ':args'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<prune-input v-if="setting.key === ':prune'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting"/>
<rate-limit-input v-if="settingGroup.key === ':rate_limit'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<!-------------------->
<span
v-if="setting.description && setting.type !== 'keyword'"
:class="inputClass"
class="expl"
v-html="getFormattedDescription(setting.description)"/>
</el-form-item>
<el-form-item v-if="setting.type !== 'keyword'" :label-width="customLabelWidth" :class="labelClass">
<span slot="label">
{{ setting.label }}
<el-tooltip v-if="canBeDeleted && isDesktop" :content="$t('settings.removeFromDB')" placement="bottom-end">
<el-button icon="el-icon-delete" circle size="mini" class="delete-setting-button" @click="removeSetting"/>
</el-tooltip>
</span>
<div class="input-row">
<el-input
v-if="setting.type === 'string' || (setting.type.includes('string') && setting.type.includes('atom'))"
:value="inputValue"
:placeholder="setting.suggestions ? setting.suggestions[0] : null"
class="input"
@input="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-switch
v-if="setting.type === 'boolean'"
:value="inputValue"
class="switch-input"
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-input-number
v-if="setting.type === 'integer'"
:value="inputValue === null ? undefined : inputValue"
:placeholder="setting.suggestions ? setting.suggestions[0].toString() : null"
:min="0"
:size="isDesktop ? 'large' : 'medium'"
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-select
v-if="setting.type === 'module' || (setting.type.includes('atom') && setting.type.includes('dropdown'))"
:value="inputValue === false ? 'false' : inputValue"
clearable
class="input"
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)">
<el-option
v-for="(option, index) in setting.suggestions"
:value="option"
:key="index"/>
</el-select>
<el-select
v-if="renderMultipleSelect(setting.type)"
:value="setting.key === ':rewrite_policy' ? rewritePolicyValue : inputValue"
multiple
filterable
allow-create
class="input"
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)">
<el-option v-for="(option, index) in setting.suggestions" :key="index" :value="option"/>
</el-select>
<el-input
v-if="setting.key === ':ip'"
:value="inputValue"
placeholder="xxx.xxx.xxx.xx"
class="input"
@input="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-input
v-if="setting.type === 'atom'"
:value="inputValue"
:placeholder="setting.suggestions[0] ? setting.suggestions[0].substr(1) : ''"
class="input"
@input="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)">
<template slot="prepend">:</template>
</el-input>
<!-- special inputs -->
<auto-linker-input v-if="settingGroup.group === ':auto_linker'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<mascots-input v-if="setting.key === ':mascots'" :data="keywordData" :setting-group="settingGroup" :setting="setting"/>
<editable-keyword-input v-if="editableKeyword(setting.key, setting.type)" :data="keywordData" :setting-group="settingGroup" :setting="setting"/>
<icons-input v-if="setting.key === ':icons'" :data="iconsData" :setting-group="settingGroup" :setting="setting"/>
<proxy-url-input v-if="setting.key === ':proxy_url'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting" :parents="settingParent"/>
<multiple-select v-if="setting.key === ':backends' || setting.key === ':args'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<prune-input v-if="setting.key === ':prune'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting"/>
<rate-limit-input v-if="settingGroup.key === ':rate_limit'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<!-------------------->
<el-tooltip v-if="canBeDeleted && isMobile" :content="$t('settings.removeFromDB')" placement="bottom-end" class="delete-setting-button-container">
<el-button icon="el-icon-delete" circle size="mini" class="delete-setting-button" @click="removeSetting"/>
</el-tooltip>
</div>
<div
v-if="setting.description && setting.type !== 'keyword'"
class="expl"
v-html="getFormattedDescription(setting.description)"/>
</el-form-item>
</div>
</template>
<script>
@ -118,13 +137,6 @@ export default {
return {}
}
},
inputClass: {
type: String,
default: function() {
return 'input-class'
},
required: false
},
labelClass: {
type: String,
default: function() {
@ -132,6 +144,13 @@ export default {
},
required: false
},
margin: {
type: Number,
default: function() {
return 0
},
required: false
},
nested: {
type: Boolean,
default: function() {
@ -185,8 +204,14 @@ export default {
return this.data[this.setting.key]
}
},
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
isMobile() {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
keywordData() {
return Array.isArray(this.data) ? this.data : []

View file

@ -3,28 +3,23 @@
<el-form ref="instanceData" :model="instanceData" :label-width="labelWidth">
<setting :setting-group="instance" :data="instanceData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="adminToken" :model="adminTokenData" :label-width="labelWidth">
<setting :setting-group="adminToken" :data="adminTokenData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="scheduledActivity" :model="scheduledActivityData" :label-width="labelWidth">
<setting :setting-group="scheduledActivity" :data="scheduledActivityData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="fetchInitialPosts" :model="fetchInitialPostsData" :label-width="labelWidth">
<setting :setting-group="fetchInitialPosts" :data="fetchInitialPostsData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="manifest" :model="manifestData" :label-width="labelWidth">
<setting :setting-group="manifest" :data="manifestData"/>
</el-form>
<div class="line"/>
<el-form ref="suggestions" :model="suggestionsData" :label-width="labelWidth">
<el-form-item label="Suggestions:"/>
<setting :setting-group="suggestions" :data="suggestionsData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="pleromaUser" :model="pleromaUserData" :label-width="labelWidth">
<setting :setting-group="pleromaUser" :data="pleromaUserData"/>
</el-form>
@ -71,7 +66,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading
@ -93,12 +88,6 @@ export default {
},
scheduledActivityData() {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.ScheduledActivity']) || {}
},
suggestions() {
return this.$store.state.settings.description.find(setting => setting.key === ':suggestions')
},
suggestionsData() {
return _.get(this.settings.settings, [':pleroma', ':suggestions']) || {}
}
},
methods: {

View file

@ -38,7 +38,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -3,15 +3,15 @@
<el-form ref="loggerData" :model="loggerData" :label-width="labelWidth">
<setting :setting-group="logger" :data="loggerData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="consoleData" :model="consoleData" :label-width="labelWidth">
<setting :setting-group="console" :data="consoleData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="exsysloggerData" :model="exsysloggerData" :label-width="labelWidth">
<setting :setting-group="exsyslogger" :data="exsysloggerData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="quackData" :model="quackData" :label-width="labelWidth">
<setting :setting-group="quack" :data="quackData"/>
</el-form>
@ -50,7 +50,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -3,15 +3,15 @@
<el-form ref="mrfSimple" :model="mrfSimpleData" :label-width="labelWidth">
<setting :setting-group="mrfSimple" :data="mrfSimpleData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="mrfRejectnonpublic" :model="mrfRejectnonpublicData" :label-width="labelWidth">
<setting :setting-group="mrfRejectnonpublic" :data="mrfRejectnonpublicData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="mrfHellthread" :model="mrfHellthreadData" :label-width="labelWidth">
<setting :setting-group="mrfHellthread" :data="mrfHellthreadData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="mrfKeyword" :model="mrfKeywordData" :label-width="labelWidth">
<setting :setting-group="mrfKeyword" :data="mrfKeywordData"/>
</el-form>
@ -21,11 +21,11 @@
<el-form ref="mrfMention" :model="mrfMentionData" :label-width="labelWidth">
<setting :setting-group="mrfMention" :data="mrfMentionData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="mrfNormalizeMarkup" :model="mrfNormalizeMarkupData" :label-width="labelWidth">
<setting :setting-group="mrfNormalizeMarkup" :data="mrfNormalizeMarkupData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="mrfVocabulary" :model="mrfVocabularyData" :label-width="labelWidth">
<setting :setting-group="mrfVocabulary" :data="mrfVocabularyData"/>
</el-form>
@ -52,7 +52,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -3,7 +3,7 @@
<el-form ref="mailer" :model="mailerData" :label-width="labelWidth">
<setting :setting-group="mailer" :data="mailerData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="emailNotifications" :model="emailNotificationsData" :label-width="labelWidth">
<setting :setting-group="emailNotifications" :data="emailNotificationsData"/>
</el-form>
@ -41,7 +41,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.$store.state.settings.loading

View file

@ -26,7 +26,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -3,7 +3,7 @@
<el-form ref="metadata" :model="metadataData" :label-width="labelWidth">
<setting :setting-group="metadata" :data="metadataData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="richMedia" :model="richMediaData" :label-width="labelWidth">
<setting :setting-group="richMedia" :data="richMediaData"/>
</el-form>
@ -30,7 +30,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -3,7 +3,7 @@
<el-form ref="teslaAdapter" :model="teslaAdapterData" :label-width="labelWidth">
<setting :setting-group="teslaAdapter" :data="teslaAdapterData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="mimeTypes" :model="mimeTypesData" :label-width="labelWidth">
<setting :setting-group="mimeTypes" :data="mimeTypesData"/>
</el-form>
@ -33,7 +33,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -32,7 +32,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.$store.state.settings.loading

View file

@ -1,13 +1,9 @@
<template>
<div v-if="!loading">
<el-row :gutter="5">
<el-col :span="8">
<el-input v-model="newRelay" :placeholder="$t('settings.followRelay')" @keyup.enter.native="followRelay"/>
</el-col>
<el-col :span="8">
<el-button type="primary" @click.native="followRelay">{{ $t('settings.follow') }}</el-button>
</el-col>
</el-row>
<div v-if="!loading" class="relays-container">
<div class="follow-relay-container">
<el-input v-model="newRelay" :placeholder="$t('settings.followRelay')" class="follow-relay" @keyup.enter.native="followRelay"/>
<el-button type="primary" @click.native="followRelay">{{ $t('settings.follow') }}</el-button>
</div>
<el-table :data="relaysTable">
<el-table-column
:label="$t('settings.instanceUrl')"

View file

@ -29,6 +29,7 @@
:nested="false"/>
</div>
<div v-if="compound(setting)">
<el-divider v-if="divideSetting(setting.key)" class="divider"/>
<div v-if="!setting.children">
<inputs
:setting-group="settingGroup"
@ -37,14 +38,19 @@
:nested="true"/>
</div>
<div v-else>
<el-form-item>
<span slot="label">
{{ setting.label }}:
<el-tooltip v-if="canBeDeleted(setting.key)" :content="$t('settings.removeFromDB')" placement="bottom-end">
<el-button icon="el-icon-delete" circle size="mini" style="margin-left:5px" @click="removeSetting(setting.key)"/>
</el-tooltip>
</span>
</el-form-item>
<div class="input-container">
<el-form-item class="grouped-settings-header">
<span slot="label">
<el-tooltip v-if="isDesktop && canBeDeleted(setting.key)" :content="$t('settings.removeFromDB')" placement="bottom-end">
<el-button icon="el-icon-delete" circle size="mini" style="margin-left:5px" @click="removeSetting(setting.key)"/>
</el-tooltip>
</span>
<span class="label-font">{{ setting.label }}</span>
</el-form-item>
<el-tooltip v-if="isMobile && canBeDeleted(setting.key)" :content="$t('settings.removeFromDB')" placement="bottom-end">
<el-button icon="el-icon-delete" circle size="mini" class="settings-delete-button" @click="removeSetting(setting.key)"/>
</el-tooltip>
</div>
<div v-for="subSetting in setting.children" :key="subSetting.key">
<inputs
:setting-group="settingGroup"
@ -54,7 +60,7 @@
:nested="true"/>
</div>
</div>
<div class="line"/>
<el-divider class="divider"/>
</div>
</div>
</div>
@ -91,6 +97,12 @@ export default {
const adapter = this.$store.state.settings.settings[':pleroma']['Pleroma.Emails.Mailer'][':adapter']
return this.settingGroup.children.filter(child => child.group && child.group.includes(adapter))
},
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
isMobile() {
return this.$store.state.app.device === 'mobile'
},
loading() {
return this.$store.state.settings.loading
}
@ -108,6 +120,9 @@ export default {
type.includes('keyword') ||
key === ':replace'
},
divideSetting(key) {
return [':sslopts', ':tlsopts', ':adapter', ':poll_limits', ':queues', ':styling', ':proxy_opts'].includes(key)
},
getFormattedDescription(desc) {
return marked(desc)
},

View file

@ -4,20 +4,20 @@
<setting :setting-group="upload" :data="uploadData"/>
</el-form>
<el-form v-if="showUploadersLocal" ref="uploadersLocal" :model="uploadersLocalData" :label-width="labelWidth">
<el-form-item class="description-container description">
<span class="description"><p>Pleroma.Uploaders.Local</p></span>
<el-form-item class="grouped-settings-header">
<span class="label-font">Pleroma.Uploaders.Local</span>
</el-form-item>
<setting :setting-group="uploadersLocal" :data="uploadersLocalData"/>
<div class="line"/>
<el-divider class="divider thick-line"/>
</el-form>
<el-form v-if="showUploadersS3" ref="uploadersS3" :model="uploadersS3Data" :label-width="labelWidth">
<setting :setting-group="uploadersS3" :data="uploadersS3Data"/>
<div class="line"/>
<el-divider class="divider thick-line"/>
</el-form>
<el-form ref="uploadFilterMogrify" :model="uploadFilterMogrifyData" :label-width="labelWidth">
<setting :setting-group="uploadFilterMogrify" :data="uploadFilterMogrifyData"/>
</el-form>
<div class="line"/>
<el-divider class="divider thick-line"/>
<el-form ref="uploadAnonymizeFilename" :model="uploadAnonymizeFilenameData" :label-width="labelWidth">
<setting :setting-group="uploadAnonymizeFilename" :data="uploadAnonymizeFilenameData"/>
</el-form>
@ -44,7 +44,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -26,7 +26,7 @@ export default {
return this.$store.state.app.device === 'mobile'
},
labelWidth() {
return this.isMobile ? '100px' : '280px'
return this.isMobile ? '120px' : '280px'
},
loading() {
return this.settings.loading

View file

@ -4,25 +4,25 @@
<div v-for="element in data" :key="getId(element)" class="setting-input">
<el-input :value="getKey(element)" placeholder="pattern" class="name-input" @input="parseEditableKeyword($event, 'key', element)"/> :
<el-input :value="getValue(element)" placeholder="replacement" class="value-input" @input="parseEditableKeyword($event, 'value', element)"/>
<el-button icon="el-icon-minus" circle @click="deleteEditableKeywordRow(element)"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" class="icon-minus-button" icon="el-icon-minus" circle @click="deleteEditableKeywordRow(element)"/>
</div>
<el-button icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
</div>
<div v-else-if="editableKeywordWithInteger">
<div v-for="element in data" :key="getId(element)" class="setting-input">
<el-input :value="getKey(element)" placeholder="key" class="name-input" @input="parseEditableKeyword($event, 'key', element)"/> :
<el-input-number :value="getValue(element)" :min="0" size="large" class="value-input" @change="parseEditableKeyword($event, 'value', element)"/>
<el-button icon="el-icon-minus" circle @click="deleteEditableKeywordRow(element)"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" class="icon-minus-button" icon="el-icon-minus" circle @click="deleteEditableKeywordRow(element)"/>
</div>
<el-button icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
</div>
<div v-else>
<div v-for="element in data" :key="getId(element)" class="setting-input">
<el-input :value="getKey(element)" placeholder="key" class="name-input" @input="parseEditableKeyword($event, 'key', element)"/> :
<el-select :value="getValue(element)" multiple filterable allow-create class="value-input" @change="parseEditableKeyword($event, 'value', element)"/>
<el-button icon="el-icon-minus" circle @click="deleteEditableKeywordRow(element)"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" class="icon-minus-button" icon="el-icon-minus" circle @click="deleteEditableKeywordRow(element)"/>
</div>
<el-button icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
</div>
</div>
</template>
@ -53,6 +53,9 @@ export default {
computed: {
editableKeywordWithInteger() {
return Array.isArray(this.setting.type) && this.setting.type.includes('keyword') && this.setting.type.includes('integer')
},
isDesktop() {
return this.$store.state.app.device === 'desktop'
}
},
methods: {

View file

@ -8,16 +8,16 @@
<el-input :value="value" placeholder="value" class="icon-value-input" @input="parseIcons($event, 'value', index, id)"/>
</div>
</div>
<el-button icon="el-icon-minus" circle class="icon-minus-button" @click="deleteIcondRow(index)"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" icon="el-icon-minus" circle class="icon-minus-button" @click="deleteIcondRow(index)"/>
</div>
<div class="icons-button-container">
<el-button icon="el-icon-plus" circle @click="addValueToIcons(index)"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" icon="el-icon-plus" circle @click="addValueToIcons(index)"/>
<span class="icons-button-desc">Add another `key - value` pair to this icon</span>
</div>
<div class="line"/>
<el-divider class="divider"/>
</div>
<div class="icons-button-container">
<el-button icon="el-icon-plus" circle @click="addIconToIcons"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" icon="el-icon-plus" circle @click="addIconToIcons"/>
<span class="icons-button-desc">Add another icon configuration</span>
</div>
</div>
@ -46,6 +46,11 @@ export default {
}
}
},
computed: {
isDesktop() {
return this.$store.state.app.device === 'desktop'
}
},
methods: {
addIconToIcons() {
const updatedValue = [...this.data, [{ key: '', value: '', id: this.generateID() }]]

View file

@ -1,20 +1,20 @@
<template>
<div>
<div v-for="mascot in data" :key="getId(mascot)" class="mascot-container">
<el-form-item label="Name" label-width="100px">
<el-form-item label="Name" label-width="85px" class="mascot-form-item">
<div class="mascot-name-container">
<el-input :value="getName(mascot)" placeholder="Name" class="mascot-name-input" @input="parseMascots($event, 'name', mascot)"/>
<el-button icon="el-icon-minus" circle @click="deleteMascotsRow(mascot)"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" class="icon-minus-button" icon="el-icon-minus" circle @click="deleteMascotsRow(mascot)"/>
</div>
</el-form-item>
<el-form-item label="URL" label-width="100px">
<el-form-item label="URL" label-width="85px" class="mascot-form-item">
<el-input :value="getUrl(mascot)" placeholder="URL" class="mascot-input" @input="parseMascots($event, 'url', mascot)"/>
</el-form-item>
<el-form-item label="Mime type" label-width="100px">
<el-form-item label="Mime type" label-width="85px" class="mascot-form-item">
<el-input :value="getMimeType(mascot)" placeholder="Mime type" class="mascot-input" @input="parseMascots($event, 'mimeType', mascot)"/>
</el-form-item>
</div>
<el-button icon="el-icon-plus" circle @click="addRowToMascots"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" icon="el-icon-plus" circle @click="addRowToMascots"/>
</div>
</template>
@ -41,6 +41,11 @@ export default {
}
}
},
computed: {
isDesktop() {
return this.$store.state.app.device === 'desktop'
}
},
methods: {
addRowToMascots() {
const updatedValue = [...this.data, { '': { ':url': '', ':mime_type': '', id: this.generateID() }}]

View file

@ -1,16 +1,20 @@
<template>
<div class="setting-input">
<div class="proxy-url-input">
<el-input
:value="proxyUrlData.host"
placeholder="host (e.g. localhost or 127.0.0.1)"
class="proxy-url-value-input"
@input="updateProxyUrl($event, 'host')"/> :
class="proxy-url-host-input"
@input="updateProxyUrl($event, 'host')"/>
<span v-if="isDesktop">:</span>
<el-input
:value="proxyUrlData.port"
placeholder="port (e.g 9020 or 3090)"
class="proxy-url-value-input"
@input="updateProxyUrl($event, 'port')"/>
<el-checkbox :value="proxyUrlData.socks5" class="name-input" @change="updateProxyUrl($event, 'socks5')">Socks5</el-checkbox>
<div class="socks5-checkbox-container">
<el-checkbox :value="proxyUrlData.socks5" @change="updateProxyUrl($event, 'socks5')"/>
<span class="socks5-checkbox">Socks5</span>
</div>
</div>
</template>
@ -47,6 +51,9 @@ export default {
}
},
computed: {
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
settings() {
return this.$store.state.settings.settings
},

View file

@ -1,6 +1,6 @@
<template>
<div>
<el-radio-group v-model="prune">
<el-radio-group v-model="prune" class="prune-options">
<el-radio label=":disabled">Disabled</el-radio>
<el-radio label=":maxlen">Limit-based</el-radio>
<el-radio label=":maxage">Time-based</el-radio>

View file

@ -13,39 +13,57 @@
class="limit-input"
@input="parseRateLimiter($event, setting.key, 'limit', 'oneLimit', rateLimitAllUsers)"/>
<div class="limit-button-container">
<el-button icon="el-icon-plus" circle @click="toggleLimits([['', ''], ['', '']], setting.key)"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" icon="el-icon-plus" circle @click="toggleLimits([['', ''], ['', '']], setting.key)"/>
<p class="expl limit-expl">Set different limits for unauthenticated and authenticated users</p>
</div>
</div>
<div v-if="rateLimitAuthUsers">
<el-form-item label="Unauthenticated users:" label-width="180px" class="rate-limit">
<el-input
:value="rateLimitUnauthUsers[0]"
placeholder="scale"
class="scale-input"
@input="parseRateLimiter($event, setting.key, 'scale', 'unauthUsersLimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/>
<span>:</span>
<el-input
:value="rateLimitUnauthUsers[1]"
placeholder="limit"
class="limit-input"
@input="parseRateLimiter($event, setting.key, 'limit', 'unauthUsersLimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/>
<el-form-item class="rate-limit">
<div class="rate-limit-label-container">
<span class="rate-limit-label">
Unauthenticated users:
</span>
</div>
<div class="rate-limit-content">
<el-input
:value="rateLimitUnauthUsers[0]"
placeholder="scale"
class="scale-input"
@input="parseRateLimiter(
$event, setting.key, 'scale', 'unauthUsersLimit', [rateLimitUnauthUsers, rateLimitAuthUsers]
)"/>
<span>:</span>
<el-input
:value="rateLimitUnauthUsers[1]"
placeholder="limit"
class="limit-input"
@input="parseRateLimiter(
$event, setting.key, 'limit', 'unauthUsersLimit', [rateLimitUnauthUsers, rateLimitAuthUsers]
)"/>
</div>
</el-form-item>
<el-form-item label="Authenticated users:" label-width="180px" class="rate-limit">
<el-input
:value="rateLimitAuthUsers[0]"
placeholder="scale"
class="scale-input"
@input="parseRateLimiter($event, setting.key, 'scale', 'authUserslimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/>
<span>:</span>
<el-input
:value="rateLimitAuthUsers[1]"
placeholder="limit"
class="limit-input"
@input="parseRateLimiter($event, setting.key, 'limit', 'authUserslimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/>
<el-form-item class="rate-limit">
<div class="rate-limit-label-container">
<span class="rate-limit-label">
Authenticated users:
</span>
</div>
<div class="rate-limit-content">
<el-input
:value="rateLimitAuthUsers[0]"
placeholder="scale"
class="scale-input"
@input="parseRateLimiter($event, setting.key, 'scale', 'authUserslimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/>
<span>:</span>
<el-input
:value="rateLimitAuthUsers[1]"
placeholder="limit"
class="limit-input"
@input="parseRateLimiter($event, setting.key, 'limit', 'authUserslimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/>
</div>
</el-form-item>
<div class="limit-button-container">
<el-button icon="el-icon-minus" circle @click="toggleLimits(['', ''], setting.key)"/>
<el-button :size="isDesktop ? 'medium' : 'mini'" class="icon-minus-button" icon="el-icon-minus" circle @click="toggleLimits(['', ''], setting.key)"/>
<p class="expl limit-expl">Set limit for all users</p>
</div>
</div>
@ -76,6 +94,9 @@ export default {
}
},
computed: {
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
rateLimitAllUsers() {
return this.data[this.setting.key] ? this.data[this.setting.key] : ['', '']
},

View file

@ -1,86 +1,132 @@
<template>
<div class="settings-container">
<div class="settings-header-container">
<h1 class="settings-header">{{ $t('settings.settings') }}</h1>
<el-link
:underline="false"
href="https://docs-develop.pleroma.social/backend/admin/config/"
target="_blank">
<el-button class="settings-docs-button">
<span>
<i class="el-icon-document"/>
{{ $t('settings.seeDocs') }}
</span>
</el-button>
</el-link>
<div v-if="isDesktop">
<div class="settings-header-container">
<h1 class="settings-header">{{ $t('settings.settings') }}</h1>
<el-link
:underline="false"
href="https://docs-develop.pleroma.social/backend/administration/CLI_tasks/config/"
target="_blank">
<el-button class="settings-docs-button">
<span>
<i class="el-icon-document"/>
{{ $t('settings.seeDocs') }}
</span>
</el-button>
</el-link>
</div>
<el-tabs v-model="activeTab" tab-position="left">
<el-tab-pane :label="$t('settings.activityPub')" :disabled="configDisabled" name="activityPub" lazy>
<activity-pub/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.auth')" :disabled="configDisabled" name="auth" lazy>
<authentication/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.autoLinker')" :disabled="configDisabled" name="autoLinker" lazy>
<auto-linker/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.esshd')" :disabled="configDisabled" name="esshd" lazy>
<esshd/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.captcha')" :disabled="configDisabled" name="captcha" lazy>
<captcha/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.frontend')" :disabled="configDisabled" name="frontend" lazy>
<frontend/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.gopher')" :disabled="configDisabled" name="gopher" lazy>
<gopher/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.http')" :disabled="configDisabled" name="http" lazy>
<http/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.instance')" :disabled="configDisabled" name="instance">
<instance/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.jobQueue')" :disabled="configDisabled" name="jobQueue" lazy>
<job-queue/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.logger')" :disabled="configDisabled" name="logger" lazy>
<logger/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.mailer')" :disabled="configDisabled" name="mailer" lazy>
<mailer/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.mediaProxy')" :disabled="configDisabled" name="mediaProxy" lazy>
<media-proxy/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.metadata')" :disabled="configDisabled" name="metadata" lazy>
<metadata/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.mrf')" :disabled="configDisabled" name="mrf" lazy>
<mrf/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.rateLimiters')" :disabled="configDisabled" name="rateLimiters" lazy>
<rate-limiters/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.relays')" lazy name="relays">
<relays/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.webPush')" :disabled="configDisabled" name="webPush" lazy>
<web-push/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.upload')" :disabled="configDisabled" name="upload" lazy>
<upload/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.other')" :disabled="configDisabled" name="other" lazy>
<other/>
</el-tab-pane>
</el-tabs>
</div>
<div v-if="isMobile">
<h1 class="settings-header">{{ $t('settings.settings') }}</h1>
<div class="settings-header-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
:underline="false"
href="https://docs-develop.pleroma.social/backend/administration/CLI_tasks/config/"
target="_blank">
<el-button class="settings-docs-button">
<span>
<i class="el-icon-document"/>
{{ $t('settings.seeDocs') }}
</span>
</el-button>
</el-link>
</div>
<activity-pub v-if="activeTab === 'activityPub'"/>
<authentication v-if="activeTab === 'auth'"/>
<auto-linker v-if="activeTab === 'autoLinker'"/>
<esshd v-if="activeTab === 'esshd'"/>
<captcha v-if="activeTab === 'captcha'"/>
<frontend v-if="activeTab === 'frontend'"/>
<gopher v-if="activeTab === 'gopher'"/>
<http v-if="activeTab === 'http'"/>
<instance v-if="activeTab === 'instance'"/>
<job-queue v-if="activeTab === 'jobQueue'"/>
<logger v-if="activeTab === 'logger'"/>
<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>
<el-tabs v-model="activeTab" tab-position="left">
<el-tab-pane :label="$t('settings.activityPub')" :disabled="configDisabled" lazy>
<activity-pub/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.auth')" :disabled="configDisabled" lazy>
<authentication/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.autoLinker')" :disabled="configDisabled" lazy>
<auto-linker/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.esshd')" :disabled="configDisabled" lazy>
<esshd/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.captcha')" :disabled="configDisabled" lazy>
<captcha/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.frontend')" :disabled="configDisabled" lazy>
<frontend/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.gopher')" :disabled="configDisabled" lazy>
<gopher/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.http')" :disabled="configDisabled" lazy>
<http/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.instance')" :disabled="configDisabled" name="instance">
<instance/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.jobQueue')" :disabled="configDisabled" lazy>
<job-queue/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.logger')" :disabled="configDisabled" lazy>
<logger/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.mailer')" :disabled="configDisabled" lazy>
<mailer/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.mediaProxy')" :disabled="configDisabled" lazy>
<media-proxy/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.metadata')" :disabled="configDisabled" lazy>
<metadata/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.mrf')" :disabled="configDisabled" lazy>
<mrf/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.rateLimiters')" :disabled="configDisabled" lazy>
<rate-limiters/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.relays')" lazy name="relays">
<relays/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.webPush')" :disabled="configDisabled" lazy>
<web-push/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.upload')" :disabled="configDisabled" lazy>
<upload/>
</el-tab-pane>
<el-tab-pane :label="$t('settings.other')" :disabled="configDisabled" lazy>
<other/>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import i18n from '@/lang'
import {
ActivityPub,
Authentication,
@ -127,6 +173,32 @@ export default {
Upload,
WebPush
},
data() {
return {
options: [
{ value: 'activityPub', label: i18n.t('settings.activityPub') },
{ value: 'auth', label: i18n.t('settings.auth') },
{ value: 'autoLinker', label: i18n.t('settings.autoLinker') },
{ 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') }
]
}
},
computed: {
activeTab: {
get() {
@ -139,6 +211,9 @@ export default {
configDisabled() {
return this.$store.state.settings.configDisabled
},
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
isMobile() {
return this.$store.state.app.device === 'mobile'
}
@ -150,30 +225,43 @@ export default {
</script>
<style rel='stylesheet/scss' lang='scss' scoped>
.settings-container {
.el-tabs {
margin-top: 20px
}
}
.settings-docs-button {
width: 163px;
text-align: left;
padding: 10px;
}
.settings-header {
margin: 0;
}
.settings-header-container {
display: flex;
height: 36px;
justify-content: space-between;
align-items: center;
margin: 22px 30px 15px 15px;
}
@media only screen and (min-width: 1824px) {
.settings-container {
.el-tabs {
margin-top: 20px
}
}
.settings-docs-button {
width: 163px;
text-align: left;
padding: 10px;
max-width: 1824px;
margin: auto;
}
}
@media only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px) {
.settings-header {
margin: 0;
margin: 7px 10px 15px 10px;
}
.settings-header-container {
display: flex;
height: 36px;
justify-content: space-between;
align-items: center;
margin: 22px 15px 15px 15px;
margin: 15px;
}
@media only screen and (min-width: 1824px) {
.settings-container {
max-width: 1824px;
margin: auto;
}
.settings-menu {
width: 163px;
}
}
</style>

View file

@ -4,6 +4,9 @@
}
.center-label label {
text-align: center;
span {
float: left;
}
}
.code {
background-color: #adbed67a;
@ -11,6 +14,9 @@
font-family: monospace;
padding: 0 3px 0 3px;
}
.delete-setting-button {
margin-left: 5px;
}
.description > p {
font-size: 14px;
color: #606266;
@ -28,8 +34,11 @@
overflow-wrap: break-word;
margin-bottom: 0;
}
.el-form-item {
margin-right: 30px;
.divider {
margin: 0 0 18px 0;
}
.divider.thick-line {
height: 2px;
}
.el-form-item .rate-limit {
margin-right: 0;
@ -38,9 +47,6 @@
padding-left: 10px;
padding-right: 10px;
}
.el-select {
width: 100%;
}
.esshd-list {
margin: 0;
}
@ -50,6 +56,8 @@
line-height: 22px;
margin: 5px 0 0 0;
overflow-wrap: break-word;
overflow: hidden;
text-overflow: ellipsis;
code {
display: inline;
line-height: 22px;
@ -57,9 +65,16 @@
padding: 2px 3px;
}
}
.follow-relay {
width: 350px;
margin-right: 7px;
}
.form-container {
margin-bottom: 80px;
}
.grouped-settings-header {
margin: 0 0 14px 0;
}
.highlight {
background-color: #e6e6e6;
}
@ -96,14 +111,31 @@
.icons-container {
display: flex;
}
.keyword-inner-input {
margin-bottom: 22px;
.input-container {
display: flex;
align-items: start;
justify-content: space-between;
.el-form-item {
margin-right: 30px;
width: 100%
}
.el-select {
width: 100%;
}
}
.keyword-container {
width: 100%
}
label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.label-font {
font-size: 14px;
color: #606266;
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei";
font-weight: 700;
}
.limit-button-container {
display: flex;
align-items: baseline;
@ -119,7 +151,7 @@
width: 100%;
height: 0;
border: 1px solid #eee;
margin-bottom: 22px;
margin-bottom: 18px;
}
.mascot-container {
margin-bottom: 15px;
@ -142,11 +174,52 @@
width: 20%;
margin-right: 8px
}
.proxy-url-input {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.proxy-url-host-input {
width: 35%;
margin-right: 8px
}
.proxy-url-value-input {
width: 35%;
margin-left: 8px;
margin-right: 10px
}
.prune-options {
display: flex;
height: 36px;
align-items: baseline;
.el-radio {
margin-top: 11px;
}
}
.rate-limit {
.el-form-item__content {
width: 100%;
display: flex;
}
}
.rate-limit-content {
width: 100%;
}
.rate-limit-label {
float: right;
}
.rate-limit-label-container {
font-size: 14px;
color: #606266;
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei";
font-weight: 700;
height: 36px;
width: 240px;
margin-right: 10px;
}
.relays-container {
margin: 0 15px;
}
.replacement-input {
width: 80%;
margin-left: 8px;
@ -156,6 +229,9 @@
width: 47%;
margin: 0 1% 5px 0
}
.settings-delete-button {
margin-left: 5px;
}
.setting-input {
display: flex;
margin-bottom: 10px;
@ -163,6 +239,20 @@
.single-input {
margin-right: 10px
}
.socks5-checkbox {
font-size: 14px;
color: #606266;
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei";
font-weight: 700;
margin-left: 10px;
}
.socks5-checkbox-container {
width: 40%;
height: 36px;
margin-right: 5px;
display: flex;
align-items: center;
}
.ssl-tls-opts {
margin: 36px 0 0 0;
}
@ -177,6 +267,9 @@
right: 0;
z-index: 10000;
}
.switch-input {
height: 36px;
}
.text {
line-height: 20px;
margin-right: 15px
@ -202,8 +295,103 @@
@media only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px) {
.el-form-item {
margin-right: 15px;
.delete-setting-button {
margin: 4px 0 0 5px;
height: 28px;
}
.delete-setting-button-container {
flex: 0 0 auto;
}
.description > p {
line-height: 18px;
margin: 0 5px 7px 0;
code {
display: inline;
line-height: 18px;
padding: 2px 3px;
font-size: 14px;
}
}
.divider {
margin: 0 0 10px 0;
}
.divider .thick-line {
height: 2px;
}
.follow-relay {
width: 70%;
margin-right: 5px;
input {
width: 100%;
}
}
.follow-relay-container {
display: flex;
justify-content: space-between;
}
.input {
flex: 1 1 auto;
}
.input-container {
width: 100%;
.el-form-item:first-child {
margin: 0;
padding: 0 15px 10px 0;
}
.el-form-item:first-child .mascot-form-item {
padding: 0;
}
.el-form-item:first-child .rate-limit {
padding: 0;
}
.settings-delete-button {
margin: 4px 15px 0 -5px;
}
}
.input-row {
display: flex;
justify-content: space-between;
}
.limit-input {
width: 40%;
}
.proxy-url-input {
flex-direction: column;
align-items: flex-start;
margin-bottom: 0;
}
.proxy-url-host-input {
width: 100%;
margin-bottom: 5px;
}
.proxy-url-value-input {
width: 100%;
margin-left: 0;
}
.prune-options {
flex-direction: column;
height: 80px;
}
.rate-limit {
.el-form-item__content {
flex-direction: column;
}
}
.rate-limit-label {
float: left;
}
.scale-input {
width: 40%;
}
.setting-label {
display: flex;
justify-content: space-between;
}
.socks5-checkbox-container {
width: 100%;
}
.submit-button {
margin: 0 15px 22px 0;
}
.el-input__inner {
padding: 0 5px 0 5px
@ -220,6 +408,34 @@
.el-select__tags {
overflow: hidden;
}
.expl, .expl > p {
line-height: 16px;
}
.icon-key-input {
width: 40%;
margin-right: 4px
}
.icon-minus-button {
width: 28px;
height: 28px;
margin-top: 4px;
}
.icon-values-container {
margin: 0 7px 7px 0;
}
.icon-value-input {
width: 60%;
margin-left: 4px;
}
.icons-button-container {
line-height: 24px;
}
.line {
margin-bottom: 10px;
}
.mascot-container {
margin-bottom: 5px;
}
.name-input {
width: 40%;
margin-right: 5px
@ -231,15 +447,14 @@
width: 40%;
margin-right: 4px
}
.relays-container {
margin: 0 10px;
}
.replacement-input {
width: 60%;
margin-left: 4px;
margin-right: 5px
}
.top-margin {
position: absolute;
top: 25%;
}
.value-input {
width: 60%;
margin-left: 5px;