admin-fe/src/views/settings/components/Inputs.vue

450 lines
20 KiB
Vue

<template>
<el-form-item :label="setting.label" :label-width="customLabelWidth">
<el-input
v-if="setting.type === 'string'"
: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"
: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(false))"
: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>
<!-- <div v-if="setting.type === 'keyword'">
<div v-for="subSetting in setting.children" :key="subSetting.key">
<inputs
:setting-group="settingGroup"
:setting="subSetting"
:data="data"
:custom-label-width="'100px'"/>
</div>
</div> -->
<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>
<editor
v-if="Array.isArray(setting.type)
&& setting.type.includes('list')
&& (setting.type.includes('tuple')
)"
v-model="editorContent"
height="150"
width="100%"
lang="elixir"
theme="chrome"/>
<el-input
v-if="setting.type === 'tuple'"
:placeholder="setting.key === ':ip' ? 'xxx.xxx.xxx.xx' : setting.suggestions[0]"
:value="data[setting.key]"
@input="updateSetting($event, settingGroup.group, settingGroup.key, setting.key)"/>
<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="editableKeywordWithInput(setting.key)">
<div v-for="([key, value], index) in editableKeywordData(data)" :key="index" class="setting-input">
<el-input :value="key" placeholder="pattern" class="name-input" @input="parseEditableKeyword($event, 'key', index)"/> :
<el-input :value="value" placeholder="replacement" class="value-input" @input="parseEditableKeyword($event, 'value', index)"/>
<el-button icon="el-icon-minus" circle @click="deleteEditableKeywordRow(index)"/>
</div>
<el-button icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
</div>
<div v-if="editableKeywordWithSelect(setting.type)">
<div v-for="([key, value], index) in editableKeywordData(data)" :key="index" class="setting-input">
<el-input :value="key" placeholder="key" class="name-input" @input="parseEditableKeyword($event, 'key', index)"/> :
<el-select :value="value" multiple filterable allow-create class="value-input" @change="parseEditableKeyword($event, 'value', index)"/>
<el-button icon="el-icon-minus" circle @click="deleteEditableKeywordRow(index)"/>
</div>
<el-button icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
</div>
<div v-if="editableKeywordWithInteger(setting.type)">
<div v-for="([key, value], index) in editableKeywordData(data)" :key="index" class="setting-input">
<el-input :value="key" placeholder="key" class="name-input" @input="parseEditableKeyword($event, 'key', index)"/> :
<el-input-number :value="value" :min="0" size="large" class="value-input" @change="parseEditableKeyword($event, 'value', index)"/>
<el-button icon="el-icon-minus" circle @click="deleteEditableKeywordRow(index)"/>
</div>
<el-button icon="el-icon-plus" circle @click="addRowToEditableKeyword"/>
</div>
<div v-if="setting.key === ':prune'">
<el-radio-group v-model="prune">
<el-radio label=":disabled">Disabled</el-radio>
<el-radio label=":maxlen">Limit-based</el-radio>
<el-radio label=":maxage">Time-based</el-radio>
</el-radio-group>
<el-form-item v-if="prune === ':maxlen'" label="max length" label-width="100" label-position="left">
<el-input-number
:value="data[setting.key][':maxlen']"
:min="0"
placeholder="1500"
size="large"
class="top-margin"
@change="updateSetting($event, settingGroup.group, settingGroup.key, setting.key)"/>
</el-form-item>
<el-form-item v-if="prune === ':maxage'" label="max age" label-width="100" label-position="left">
<el-input-number
:value="data[setting.key][':maxage']"
:min="0"
placeholder="3600"
size="large"
class="top-margin"
@change="updateSetting($event, settingGroup.group, settingGroup.key, setting.key)"/>
</el-form-item>
</div>
<div v-if="settingGroup.key === ':rate_limit'">
<div v-if="!rateLimitAuthUsers">
<el-input :value="rateLimitAllUsers[0]" placeholder="scale" class="scale-input" @input="parseRateLimiter($event, setting.key, 'scale', 'oneLimit', rateLimitAllUsers)"/> :
<el-input :value="rateLimitAllUsers[1]" placeholder="limit" 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([{ 'tuple': [null, null] }, { 'tuple': [null, null] }], 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="Authenticated users:">
<el-input :value="rateLimitAuthUsers[0]" placeholder="scale" class="scale-input" @input="parseRateLimiter($event, setting.key, 'scale', 'authUserslimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/> :
<el-input :value="rateLimitAuthUsers[1]" placeholder="limit" class="limit-input" @input="parseRateLimiter($event, setting.key, 'limit', 'authUserslimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/>
</el-form-item>
<el-form-item label="Unauthenticated users:">
<el-input :value="rateLimitUnauthUsers[0]" placeholder="scale" class="scale-input" @input="parseRateLimiter($event, setting.key, 'scale', 'unauthUsersLimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/> :
<el-input :value="rateLimitUnauthUsers[1]" placeholder="limit" class="limit-input" @input="parseRateLimiter($event, setting.key, 'limit', 'unauthUsersLimit', [rateLimitUnauthUsers, rateLimitAuthUsers])"/>
</el-form-item>
<div class="limit-button-container">
<el-button icon="el-icon-minus" circle @click="toggleLimits({ 'tuple': [null, null] }, setting.key)"/>
<p class="expl limit-expl">Set limit for all users</p>
</div>
</div>
</div>
<div v-if="setting.key === ':proxy_url'" class="setting-input">
<el-checkbox v-model="proxyUrlTypeSocks5" class="name-input" border>Socks5</el-checkbox>
<el-input
:value="proxyUrlData"
:placeholder="setting.suggestions ? setting.suggestions[0] : ''"
class="value-input"
@input="updateSetting($event, settingGroup.group, settingGroup.key, setting.key)"/>
</div>
<div v-if="settingGroup.group === ':auto_linker' && (setting.key === ':class' || setting.key === ':rel')">
<el-switch :value="autoLinkerBooleanValue(setting.key)" @change="processAutoLinker($event, 'auto_linker', 'opts', 'class')"/>
<el-input v-if="autoLinkerBooleanValue(setting.key)" :value="autoLinkerStringValue(setting.key)" @input="processAutoLinker($event, settingGroup.key, ':opts', setting.key)"/>
</div>
<div v-if="settingGroup.group === ':auto_linker' && (setting.key === ':truncate')">
<el-switch :value="autoLinkerBooleanValue(setting.key)" @change="processAutoLinker($event, 'auto_linker', 'opts', 'class')"/>
<el-input-number v-if="autoLinkerBooleanValue(setting.key)" :value="autoLinkerIntegerValue(setting.key)" @input="processAutoLinker($event, settingGroup.key, ':opts', setting.key)"/>
</div>
<div v-if="setting.key === ':mascots'">
<div v-for="([name, url, mimeType], index) in mascotsValue" :key="index" class="mascot-container">
<div class="mascot-name-container">
<el-input :value="name" placeholder="Name" class="mascot-name-input" @input="parseMascots($event, 'name', index)"/>
<el-button icon="el-icon-minus" circle @click="deleteMascotsRow(index, 'emoji', 'groups')"/>
</div>
<el-input :value="url" placeholder="URL" class="mascot-input" @input="parseMascots($event, 'url', index)"/>
<el-input :value="mimeType" placeholder="Mime type" class="mascot-input" @input="parseMascots($event, 'mimeType', index)"/>
</div>
<el-button icon="el-icon-plus" circle @click="addRowToMascots"/>
</div>
<div v-if="setting.key === ':icons'">
<div v-for="(icon, index) in iconsValue" :key="index" class="mascot-container">
<div v-for="([key, value], index) in icon" :key="index" class="setting-input">
<el-input :value="key" placeholder="key" class="name-input" @input="parseIcons($event, 'key', index)"/> :
<el-input :value="value" placeholder="value" class="value-input" @input="parseIcons($event, 'value', index)"/>
<el-button icon="el-icon-minus" circle @click="deleteIcondRow(index)"/>
</div>
<div class="icons-button-container">
<el-button icon="el-icon-plus" circle @click="addValueToIcons"/>
<span class="icons-button-desc">Add another `key - value` pair to this icon</span>
</div>
<div class="icons-button-container">
<el-button icon="el-icon-plus" circle @click="addIconToIcons"/>
<span class="icons-button-desc">Add another icon configuration</span>
</div>
</div>
</div>
<p class="expl">{{ setting.description }}</p>
</el-form-item>
</template>
<script>
import AceEditor from 'vue2-ace-editor'
import 'brace/mode/elixir'
import 'default-passive-events'
export default {
name: 'Inputs',
components: {
editor: AceEditor
},
props: {
customLabelWidth: {
type: String,
default: function() {
return this.labelWidth
},
required: false
},
data: {
type: Object || Array,
default: function() {
return {}
}
},
nested: {
type: Boolean,
default: function() {
return false
}
},
setting: {
type: Object,
default: function() {
return {}
}
},
settingGroup: {
type: Object,
default: function() {
return {}
}
},
settingParent: {
type: Object,
default: function() {
return {}
},
required: false
}
},
computed: {
editorContent: {
get: function() {
return this.data[this.setting.key] ? this.data[this.setting.key][0] : ''
},
set: function(value) {
this.processNestedData([value], this.settingGroup.key, this.setting.key, this.data[this.setting.key])
}
},
iconsValue() {
return this.data[':icons']
? this.data[':icons'].map(icon => Object.keys(icon).map(key => [key, icon[key]]))
: null
},
inputValue() {
if ([':esshd', ':cors_plug', ':quack', ':http_signatures'].includes(this.settingGroup.group) &&
this.data[this.setting.key]) {
return this.data[this.setting.key].value
} else if ((this.settingGroup.group === ':logger' && this.setting.key === ':backends') ||
this.setting.key === 'Pleroma.Web.Auth.Authenticator') {
return this.data.value
} else {
return this.data[this.setting.key]
}
},
labelWidth() {
return this.isMobile ? '100px' : '240px'
},
mascotsValue() {
return Object.keys(this.data)
.map(mascotName =>
[mascotName, this.data[mascotName][':url'], this.data[mascotName][':mime_type']])
},
proxyUrlData() {
if (!this.data[this.setting.key]) {
return null
} else {
return typeof this.data[this.setting.key] === 'string'
? this.data[this.setting.key]
: `${this.data[this.setting.key][1]}:${this.data[this.setting.key][2]}`
}
},
proxyUrlTypeSocks5() {
return Array.isArray(this.data[this.setting.key]) && this.data[this.setting.key][0] === 'socks5'
},
prune() {
return this.data[this.setting.key] === ':disabled'
? ':disabled'
: Object.keys(this.data[this.setting.key])[0]
},
rateLimitAllUsers() {
return this.data[this.setting.key] ? Object.entries(this.data[this.setting.key])[0] : [null, null]
},
rateLimitAuthUsers() {
return Array.isArray(this.data[this.setting.key])
? Object.entries(this.data[this.setting.key][1])[0]
: false
},
rateLimitUnauthUsers() {
return Array.isArray(this.data[this.setting.key])
? Object.entries(this.data[this.setting.key][0])[0]
: false
},
rewritePolicyValue() {
return typeof this.data[this.setting.key] === 'string' ? [this.data[this.setting.key]] : this.data[this.setting.key]
}
},
methods: {
addIconToIcons() {},
addValueToIcons() {},
addRowToEditableKeyword() {
const updatedValue = this.editableKeywordData(this.data).reduce((acc, el, i) => {
return { ...acc, [el[0]]: el[1] }
}, {})
this.updateSetting({ ...updatedValue, '': [] }, this.settingGroup.group, this.settingGroup.key, this.setting.key)
},
addRowToMascots() {
const updatedValue = this.data[':mascots'].reduce((acc, el, i) => {
return { ...acc, [el[0]]: { url: el[1], mime_type: el[2] }}
}, {})
this.updateSetting({ ...updatedValue, '': { url: '', mime_type: '' }}, this.settingGroup.group, 'assets', 'mascots')
},
autoLinkerBooleanValue(key) {
const value = this.data[this.setting.key]
return typeof value === 'string' || typeof value === 'number'
},
autoLinkerIntegerValue(key) {
const value = this.data[this.setting.key]
return value || 0
},
autoLinkerStringValue(key) {
const value = this.data[this.setting.key]
return value || ''
},
deleteEditableKeywordRow(index) {
const filteredValues = this.editableKeywordData(this.data).filter((el, i) => index !== i)
const updatedValue = filteredValues.reduce((acc, el, i) => {
return { ...acc, [el[0]]: el[1] }
}, {})
console.log(updatedValue)
this.updateSetting(updatedValue, this.settingGroup.group, this.settingGroup.key, this.setting.key)
},
deleteIcondRow(index) {},
deleteMascotsRow(index) {
const filteredValues = this.data[':mascots'].filter((el, i) => index !== i)
const updatedValue = filteredValues.reduce((acc, el, i) => {
return { ...acc, [el[0]]: { url: el[1], mime_type: el[2] }}
}, {})
this.updateSetting(updatedValue, this.settingGroup.group, 'assets', 'mascots')
},
editableKeywordWithInput(key) {
return key === ':replace'
},
editableKeywordWithInteger(type) {
return Array.isArray(type)
? type.includes('keyword') && type.includes('integer')
: false
},
editableKeywordWithSelect(type) {
return type === 'map' ||
(Array.isArray(type) && type.includes('keyword') && type.findIndex(el => el.includes('list') && el.includes('string')) !== -1)
},
editableKeywordData(data) {
return Object.keys(data).map(key => [key, data[key]])
},
parseEditableKeyword(value, inputType, index) {
const updatedValue = this.editableKeywordData(this.data).reduce((acc, el, i) => {
if (index === i) {
return inputType === 'key' ? { ...acc, [value]: el[1] } : { ...acc, [el[0]]: value }
}
return { ...acc, [el[0]]: el[1] }
}, {})
console.log(updatedValue)
this.updateSetting(updatedValue, this.settingGroup.group, this.settingGroup.key, this.setting.key)
},
parseIcons(value, inputType, index) {},
parseMascots(value, inputType, index) {
const updatedValue = this.data[':mascots'].reduce((acc, el, i) => {
if (index === i) {
if (inputType === 'name') {
return { ...acc, [value]: { url: el[1], mime_type: el[2] }}
} else if (inputType === 'url') {
return { ...acc, [el[0]]: { url: value, mime_type: el[2] }}
} else {
return { ...acc, [el[0]]: { url: el[1], mime_type: value }}
}
}
return { ...acc, [el[0]]: { url: el[1], mime_type: el[2] }}
}, {})
this.updateSetting(updatedValue, this.settingGroup.group, 'assets', 'mascots')
},
parseRateLimiter(value, input, typeOfInput, typeOfLimit, currentValue) {
if (typeOfLimit === 'oneLimit') {
const valueToSend = typeOfInput === 'scale' ? { 'tuple': [value, currentValue[1]] } : { 'tuple': [currentValue[0], value] }
this.updateSetting(valueToSend, this.settingGroup.group, 'rate_limit', input)
} else if (typeOfLimit === 'authUserslimit') {
const valueToSend = typeOfInput === 'scale'
? [{ 'tuple': [currentValue[0][0], currentValue[0][1]] }, { 'tuple': [value, currentValue[1][1]] }]
: [{ 'tuple': [currentValue[0][0], currentValue[0][1]] }, { 'tuple': [currentValue[1][0], value] }]
this.updateSetting(valueToSend, this.settingGroup.group, 'rate_limit', input)
} else if (typeOfLimit === 'unauthUsersLimit') {
const valueToSend = typeOfInput === 'scale'
? [{ 'tuple': [value, currentValue[0][1]] }, { 'tuple': [currentValue[1][0], currentValue[1][1]] }]
: [{ 'tuple': [currentValue[0][0], value] }, { 'tuple': [currentValue[1][0], currentValue[1][1]] }]
this.updateSetting(valueToSend, this.settingGroup.group, 'rate_limit', input)
}
},
processAutoLinker(value, tab, inputName, childName) {
},
processNestedData(value, group, key, parentInput, parentType, childInput, childType) {
const updatedValueForState = { ...this.$store.state.settings.settings[group][key][parentInput], ...{ [childInput]: value }}
const updatedValue = this.$store.state.settings.updatedSettings[group]
? { ...this.$store.state.settings.updatedSettings[group][key][parentInput][1], ...{ [childInput]: [childType, value] }}
: { [childInput]: [childType, value] }
this.$store.dispatch('UpdateSettings', { group, key, input: parentInput, value: updatedValue, type: parentType })
this.$store.dispatch('UpdateState', { group, key, input: parentInput, value: updatedValueForState })
},
renderMultipleSelect(type) {
return Array.isArray(type) && (
type.includes('module') ||
(type.includes('list') && type.includes('string')) ||
(type.includes('list') && type.includes('atom')) ||
(type.includes('regex') && type.includes('string')) ||
this.setting.key === ':args'
)
},
toggleAtomTuple(value, tab, input) {
console.log(value)
},
toggleLimits(value, input) {
this.updateSetting(value, this.settingGroup.group, 'rate_limit', input)
},
update(value, group, key, parent, input, type, nested) {
nested
? this.processNestedData(value, group, key, parent.key, parent.type, input, type)
: this.updateSetting(value, group, key, input, type)
},
updateSetting(value, group, key, input, type) {
this.$store.dispatch('UpdateSettings', { group, key, input, value, type })
this.$store.dispatch('UpdateState', { group, key, input, value })
}
}
}
</script>
<style rel='stylesheet/scss' lang='scss'>
@import '../styles/main';
@include settings
</style>