Merge branch 'admin-tabs-2' into 'develop'
Most of the remaining admin tabs See merge request pleroma/pleroma-fe!2187
This commit is contained in:
commit
aa426b3d14
114 changed files with 4924 additions and 952 deletions
|
|
@ -29,9 +29,9 @@ const copyPlugin = ({ inUrl, inFs }) => {
|
|||
order: 'post',
|
||||
sequential: true,
|
||||
async handler () {
|
||||
console.log(`Copying '${inFs}' to ${copyTarget}...`)
|
||||
console.info(`Copying '${inFs}' to ${copyTarget}...`)
|
||||
await cp(inFs, copyTarget, { recursive: true })
|
||||
console.log('Done.')
|
||||
console.info('Done.')
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ export const buildSwPlugin = ({
|
|||
order: 'post',
|
||||
sequential: true,
|
||||
async handler () {
|
||||
console.log('Building service worker for production')
|
||||
console.info('Building service worker for production')
|
||||
await build(config)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
changelog.d/admin_tab.add
Normal file
2
changelog.d/admin_tab.add
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Most of the remaining AdminFE tabs were added into Admin Dashboard
|
||||
It's now possible to customize PWA Manfiest from PleromaFE
|
||||
16
src/App.scss
16
src/App.scss
|
|
@ -513,6 +513,12 @@ nav {
|
|||
}
|
||||
}
|
||||
|
||||
label {
|
||||
&.-disabled {
|
||||
color: var(--textFaint);
|
||||
}
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
border: none;
|
||||
|
|
@ -553,6 +559,10 @@ textarea {
|
|||
&[disabled="disabled"],
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
color: var(--textFaint);
|
||||
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
&[type="range"] {
|
||||
|
|
@ -578,6 +588,8 @@ textarea {
|
|||
& + label::before {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
+ label::before {
|
||||
|
|
@ -677,7 +689,8 @@ option {
|
|||
list-style: none;
|
||||
display: grid;
|
||||
grid-auto-flow: row dense;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-columns: repeat(auto-fit, minmax(20em, 1fr));
|
||||
grid-gap: 0.5em;
|
||||
|
||||
li {
|
||||
border: 1px solid var(--border);
|
||||
|
|
@ -698,7 +711,6 @@ option {
|
|||
--_roundness-right: 0;
|
||||
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
> *:first-child,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<label
|
||||
class="checkbox"
|
||||
:class="[{ disabled, indeterminate, 'indeterminate-fix': indeterminateTransitionFix }, radio ? '-radio' : '-checkbox']"
|
||||
:class="[{ ['-disabled']: disabled, indeterminate, 'indeterminate-fix': indeterminateTransitionFix }, radio ? '-radio' : '-checkbox']"
|
||||
>
|
||||
<span
|
||||
v-if="!!$slots.before"
|
||||
|
|
@ -123,7 +123,7 @@ export default {
|
|||
|
||||
.disabled {
|
||||
.checkbox-indicator::before {
|
||||
background-color: var(--background);
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,28 @@
|
|||
<template>
|
||||
<div class="font-control">
|
||||
<Checkbox
|
||||
v-if="typeof fallback !== 'undefined'"
|
||||
:id="name + '-o'"
|
||||
class="font-checkbox"
|
||||
:model-value="present"
|
||||
@change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
|
||||
>
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="settings.style.fonts.override"
|
||||
tag="span"
|
||||
<div class="setting-item">
|
||||
<Checkbox
|
||||
v-if="typeof fallback !== 'undefined'"
|
||||
:id="name + '-o'"
|
||||
class="font-checkbox setting-control setting-label"
|
||||
:model-value="present"
|
||||
@change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
|
||||
>
|
||||
{{ label }}
|
||||
</i18n-t>
|
||||
</Checkbox>
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="settings.style.fonts.override"
|
||||
tag="span"
|
||||
>
|
||||
<span>
|
||||
{{ label }}
|
||||
</span>
|
||||
</i18n-t>
|
||||
</Checkbox>
|
||||
</div>
|
||||
{{ ' ' }}
|
||||
<div
|
||||
v-if="modelValue?.family"
|
||||
class="font-input"
|
||||
class="font-input setting-item"
|
||||
>
|
||||
<label
|
||||
v-if="manualEntry"
|
||||
|
|
@ -69,7 +73,7 @@
|
|||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="btn-group"
|
||||
class="font-selector btn-group"
|
||||
>
|
||||
<button
|
||||
class="btn button-default"
|
||||
|
|
@ -132,18 +136,6 @@
|
|||
<script src="./font_control.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
.font-control {
|
||||
.custom-font {
|
||||
min-width: 20em;
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
.font-input {
|
||||
margin-left: 2em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.invalid-tooltip {
|
||||
margin: 0.5em 1em;
|
||||
min-width: 10em;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import localeService from '../../services/locale/locale.service.js'
|
|||
import Select from '../select/select.vue'
|
||||
import ProfileSettingIndicator from 'src/components/settings_modal/helpers/profile_setting_indicator.vue'
|
||||
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Select,
|
||||
|
|
@ -26,7 +28,9 @@ export default {
|
|||
languages () {
|
||||
return localeService.languages
|
||||
},
|
||||
|
||||
uniqueId () {
|
||||
return uuidv4()
|
||||
},
|
||||
controlledLanguage: {
|
||||
get: function () {
|
||||
return Array.isArray(this.modelValue) ? this.modelValue : [this.modelValue]
|
||||
|
|
|
|||
|
|
@ -1,30 +1,32 @@
|
|||
<template>
|
||||
<div class="interface-language-switcher">
|
||||
<label>
|
||||
<slot />
|
||||
<ProfileSettingIndicator :is-profile="profile" />
|
||||
</label>
|
||||
<ul class="setting-list">
|
||||
<li
|
||||
v-for="index of controlledLanguage.keys()"
|
||||
:key="index"
|
||||
<ul class="interface-language-switcher setting-list">
|
||||
<li
|
||||
v-for="index of controlledLanguage.keys()"
|
||||
:key="index"
|
||||
class="setting-item"
|
||||
>
|
||||
<label
|
||||
class="setting-label"
|
||||
:for="uniqueId+index"
|
||||
>
|
||||
<label>
|
||||
{{ index === 0 ? $t('settings.primary_language') : $t('settings.fallback_language', { index }, index) }}
|
||||
<Select
|
||||
class="language-select"
|
||||
:model-value="controlledLanguage[index]"
|
||||
@update:model-value="val => setLanguageAt(index, val)"
|
||||
{{ index === 0 ? $t('settings.primary_language') : $t('settings.fallback_language', { index }, index) }}
|
||||
</label>
|
||||
<span class="setting-control btn-group">
|
||||
<Select
|
||||
:id="uniqueId+index"
|
||||
:name="uniqueId+index"
|
||||
class="language-select"
|
||||
:model-value="controlledLanguage[index]"
|
||||
@update:model-value="val => setLanguageAt(index, val)"
|
||||
>
|
||||
<option
|
||||
v-for="lang in languages"
|
||||
:key="lang.code"
|
||||
:value="lang.code"
|
||||
>
|
||||
<option
|
||||
v-for="lang in languages"
|
||||
:key="lang.code"
|
||||
:value="lang.code"
|
||||
>
|
||||
{{ lang.name }}
|
||||
</option>
|
||||
</Select>
|
||||
</label>
|
||||
{{ lang.name }}
|
||||
</option>
|
||||
</Select>
|
||||
<button
|
||||
v-if="controlledLanguage.length > 1 && index !== 0"
|
||||
class="button-default btn"
|
||||
|
|
@ -32,25 +34,53 @@
|
|||
>
|
||||
{{ $t('settings.remove_language') }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
class="button-default btn"
|
||||
@click="addLanguage"
|
||||
>
|
||||
{{ $t('settings.add_language') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
<li class="add-button">
|
||||
<button
|
||||
class="button-default btn"
|
||||
@click="addLanguage"
|
||||
>
|
||||
{{ $t('settings.add_language') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script src="./interface_language_switcher.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
.interface-language-switcher {
|
||||
.language-select {
|
||||
margin-right: 1em;
|
||||
.setting-list {
|
||||
.setting-item {
|
||||
display: grid;
|
||||
grid-template-columns: subgrid;
|
||||
}
|
||||
}
|
||||
|
||||
.add-button {
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding-bottom: 1em;
|
||||
|
||||
.default-button {
|
||||
display: block;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.-mobile & {
|
||||
li.setting-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5em;
|
||||
align-items: stretch;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.add-button {
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@
|
|||
}
|
||||
|
||||
form textarea {
|
||||
line-height: 16px;
|
||||
line-height: 1;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
/* TODO fix order of styles */
|
||||
label.Select {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
|
||||
select {
|
||||
appearance: none;
|
||||
|
|
@ -33,13 +34,12 @@ label.Select {
|
|||
border: none;
|
||||
color: var(--text);
|
||||
margin: 0;
|
||||
padding: 0 2em 0 0.2em;
|
||||
padding: 0 2em 0 0.5em;
|
||||
font-family: var(--font);
|
||||
font-size: 1em;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
height: 2em;
|
||||
line-height: 16px;
|
||||
line-height: 2;
|
||||
|
||||
&[multiple],
|
||||
&[size] {
|
||||
|
|
@ -79,7 +79,7 @@ label.Select {
|
|||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 5px;
|
||||
right: 0.5em;
|
||||
height: 100%;
|
||||
width: 0.875em;
|
||||
font-family: var(--font);
|
||||
|
|
|
|||
39
src/components/settings_modal/admin_tabs/auth_tab.js
Normal file
39
src/components/settings_modal/admin_tabs/auth_tab.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import TupleSetting from '../helpers/tuple_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
import MapSetting from '../helpers/map_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const AuthTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
TupleSetting,
|
||||
AttachmentSetting,
|
||||
GroupSetting,
|
||||
ListSetting,
|
||||
MapSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject(),
|
||||
LDAPEnabled () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma'][':ldap'][':enabled']
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthTab
|
||||
105
src/components/settings_modal/admin_tabs/auth_tab.vue
Normal file
105
src/components/settings_modal/admin_tabs/auth_tab.vue
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.job_queues')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.auth.MFA') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.auth.TOTP') }}</h4>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:instance.:multi_factor_authentication.:totp.:digits" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:instance.:multi_factor_authentication.:totp.:period" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.auth.backup_codes') }}</h4>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:instance.:multi_factor_authentication.:backup_codes.:number" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:instance.:multi_factor_authentication.:backup_codes.:length" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<GroupSetting path=":pleroma.:instance.:multi_factor_authentication" />
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.auth.OAuth') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:auth.:auth_template" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:auth.:enforce_oauth_admin_scope_usage" />
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:auth.:oauth_consumer_template" />
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting path=":pleroma.:auth.:oauth_consumer_strategies" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:oauth2.:token_expires_in" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:oauth2.:issue_new_refresh_token" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:oauth2.:clean_expired_tokens" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.auth.LDAP') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:ldap.:enabled" />
|
||||
</li>
|
||||
<template v-if="LDAPEnabled">
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:ldap.:host" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:ldap.:port" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:ldap.:tls" />
|
||||
</li>
|
||||
<li>
|
||||
<!-- CONFIRM old admin FE only supports ONE setting which is Verify, is that correct or should we allow more than one? -->
|
||||
<MapSetting
|
||||
:allow-new="false"
|
||||
path=":pleroma.:ldap.:tlsopts"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:ldap.:ssl" />
|
||||
</li>
|
||||
<li>
|
||||
<!-- CONFIRM old admin FE only supports ONE setting which is Verify, is that correct or should we allow more than one? -->
|
||||
<MapSetting
|
||||
:allow-new="false"
|
||||
path=":pleroma.:ldap.:sslopts"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:ldap.:base" />
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:ldap.:uid" />
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:ldap.:cacertfile" />
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:ldap.:mail" />
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- CONFIRM admin token is present in AdminFE but missing in both data and descriptions?? -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./auth_tab.js"></script>
|
||||
|
|
@ -10,6 +10,22 @@ import ModifiedIndicator from '../helpers/modified_indicator.vue'
|
|||
import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faArrowsRotate,
|
||||
faFolderOpen,
|
||||
faServer,
|
||||
faDownload
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faArrowsRotate,
|
||||
faFolderOpen,
|
||||
faDownload,
|
||||
faServer
|
||||
)
|
||||
|
||||
const EmojiTab = {
|
||||
components: {
|
||||
TabSwitcher,
|
||||
|
|
@ -44,10 +60,12 @@ const EmojiTab = {
|
|||
},
|
||||
|
||||
computed: {
|
||||
...SharedComputedObject(),
|
||||
pack () {
|
||||
return this.packName !== '' ? this.knownPacks[this.packName] : undefined
|
||||
},
|
||||
packMeta () {
|
||||
if (this.packName === '') return {}
|
||||
if (this.editedMetadata[this.packName] === undefined) {
|
||||
this.editedMetadata[this.packName] = clone(this.pack.pack)
|
||||
}
|
||||
|
|
@ -98,8 +116,6 @@ const EmojiTab = {
|
|||
return Promise.reject(resp)
|
||||
}
|
||||
}).then(() => {
|
||||
this.$refs.createPackPopover.hidePopover()
|
||||
|
||||
this.packName = this.newPackName
|
||||
this.newPackName = ''
|
||||
})
|
||||
|
|
@ -205,8 +221,6 @@ const EmojiTab = {
|
|||
for (const pack in this.knownRemotePacks[inst]) {
|
||||
this.sortPackFiles(`${pack}@${inst}`)
|
||||
}
|
||||
|
||||
this.$refs.remotePackPopover.hidePopover()
|
||||
})
|
||||
.catch(data => {
|
||||
this.displayError(data)
|
||||
|
|
@ -223,8 +237,6 @@ const EmojiTab = {
|
|||
.then(data => data.json())
|
||||
.then(resp => {
|
||||
if (resp === 'ok') {
|
||||
this.$refs.downloadPackPopover.hidePopover()
|
||||
|
||||
return this.refreshPackList()
|
||||
} else {
|
||||
this.displayError(resp.error)
|
||||
|
|
@ -242,8 +254,6 @@ const EmojiTab = {
|
|||
.then(data => data.json())
|
||||
.then(resp => {
|
||||
if (resp === 'ok') {
|
||||
this.$refs.additionalRemotePopover.hidePopover()
|
||||
|
||||
return this.refreshPackList()
|
||||
} else {
|
||||
this.displayError(resp.error)
|
||||
|
|
@ -262,8 +272,6 @@ const EmojiTab = {
|
|||
.then(data => data.json())
|
||||
.then(resp => {
|
||||
if (resp === 'ok') {
|
||||
this.$refs.additionalRemotePopover.hidePopover()
|
||||
|
||||
return this.refreshPackList()
|
||||
} else {
|
||||
this.displayError(resp.error)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,54 @@
|
|||
.emoji-tab {
|
||||
.btn-group .btn:not(:first-child) {
|
||||
margin-left: 0.5em;
|
||||
.EmojiTab {
|
||||
.setting-list {
|
||||
margin: 0.5em 2em;
|
||||
}
|
||||
|
||||
.pack-info-wrapper {
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
|
||||
.header-buttons {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
justify-content: end;
|
||||
align-items: end;
|
||||
|
||||
&:not(.btn-group) {
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.header-text {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.button-default {
|
||||
flex: 0 0 auto;
|
||||
padding: 0.5em;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.popover-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.selector-buttons,
|
||||
.meta-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
h3.toolbar {
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.emoji-info-input {
|
||||
|
|
@ -18,8 +62,8 @@
|
|||
}
|
||||
|
||||
.emoji {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
}
|
||||
|
||||
.emoji-unsaved {
|
||||
|
|
@ -30,6 +74,22 @@
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1em;
|
||||
|
||||
.button-unstyled {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.emoji-item,
|
||||
.placeholder {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
background: var(--textFaint);
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,168 +1,75 @@
|
|||
<template>
|
||||
<div
|
||||
class="emoji-tab"
|
||||
class="EmojiTab"
|
||||
:label="$t('admin_dash.tabs.emoji')"
|
||||
>
|
||||
<div class="setting-item">
|
||||
<h2>{{ $t('admin_dash.tabs.emoji') }}</h2>
|
||||
<div class="setting-section">
|
||||
<h3 class="toolbar">
|
||||
<span class="header-text">
|
||||
{{ $t('admin_dash.emoji.emoji_packs') }}
|
||||
</span>
|
||||
|
||||
<ul class="setting-list">
|
||||
<h3>{{ $t('admin_dash.emoji.global_actions') }}</h3>
|
||||
|
||||
<li class="btn-group setting-item">
|
||||
<span class="header-buttons btn-group">
|
||||
<button
|
||||
class="button button-default btn"
|
||||
class="button button-default"
|
||||
type="button"
|
||||
:title="$t('admin_dash.emoji.reload')"
|
||||
@click="reloadEmoji"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.reload') }}
|
||||
</button>
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="importFromFS"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.importFS') }}
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<li class="btn-group setting-item">
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="$refs.remotePackPopover.showPopover"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.remote_packs') }}
|
||||
|
||||
<Popover
|
||||
ref="remotePackPopover"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
>
|
||||
<template #content>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<h3>{{ $t('admin_dash.emoji.remote_pack_instance') }}</h3>
|
||||
<input
|
||||
v-model="remotePackInstance"
|
||||
class="input"
|
||||
:placeholder="$t('admin_dash.emoji.remote_pack_instance')"
|
||||
>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="listRemotePacks"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.do_list') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</button>
|
||||
<button
|
||||
class="button button-default emoji-panel-additional-actions"
|
||||
@click="$refs.additionalRemotePopover.showPopover"
|
||||
>
|
||||
<FAIcon
|
||||
icon="chevron-down"
|
||||
/>
|
||||
|
||||
<Popover
|
||||
ref="additionalRemotePopover"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
>
|
||||
<template #content>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<h3>{{ $t('admin_dash.emoji.new_pack_name') }}</h3>
|
||||
<input
|
||||
v-model="newPackName"
|
||||
:placeholder="$t('admin_dash.emoji.new_pack_name')"
|
||||
class="input"
|
||||
>
|
||||
<h3>Import pack from URL</h3>
|
||||
<input
|
||||
v-model="remotePackURL"
|
||||
class="input"
|
||||
placeholder="Pack .zip URL"
|
||||
>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
:disabled="newPackName.trim() === '' || remotePackURL.trim() === ''"
|
||||
@click="downloadRemoteURLPack"
|
||||
>
|
||||
Import
|
||||
</button>
|
||||
<h3>Import pack from a file</h3>
|
||||
<input
|
||||
type="file"
|
||||
accept="application/zip"
|
||||
class="emoji-tab-popover-file input"
|
||||
@change="remotePackFile = $event.target.files"
|
||||
>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
:disabled="newPackName.trim() === '' || remotePackFile === null || remotePackFile.length === 0"
|
||||
@click="downloadRemoteFilePack"
|
||||
>
|
||||
Import
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<h3>{{ $t('admin_dash.emoji.emoji_packs') }}</h3>
|
||||
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.emoji.edit_pack') }}</h4>
|
||||
|
||||
<Select
|
||||
v-model="packName"
|
||||
class="form-control"
|
||||
>
|
||||
<option
|
||||
value=""
|
||||
disabled
|
||||
hidden
|
||||
>
|
||||
{{ $t('admin_dash.emoji.emoji_pack') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="(pack, listPackName) in knownPacks"
|
||||
:key="listPackName"
|
||||
:label="listPackName"
|
||||
>
|
||||
{{ listPackName }}
|
||||
</option>
|
||||
</Select>
|
||||
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="$refs.createPackPopover.showPopover"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.create_pack') }}
|
||||
<FAIcon icon="arrows-rotate" />
|
||||
{{ $t('admin_dash.emoji.reload_short') }}
|
||||
</button>
|
||||
<Popover
|
||||
ref="createPackPopover"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
>
|
||||
<template #trigger>
|
||||
<button
|
||||
class="button button-default"
|
||||
type="button"
|
||||
:title="$t('admin_dash.emoji.remote_packs')"
|
||||
>
|
||||
<FAIcon icon="download" />
|
||||
{{ $t('admin_dash.emoji.remote_packs_short') }}
|
||||
</button>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<h3>{{ $t('admin_dash.emoji.remote_pack_instance') }}</h3>
|
||||
<input
|
||||
v-model="remotePackInstance"
|
||||
class="input"
|
||||
:placeholder="$t('admin_dash.emoji.remote_pack_instance')"
|
||||
>
|
||||
<button
|
||||
class="button button-default emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="listRemotePacks"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.do_list') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
|
||||
<Popover
|
||||
ref="additionalRemotePopover"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
>
|
||||
<template #trigger>
|
||||
<button
|
||||
class="button button-default emoji-panel-additional-actions"
|
||||
:title="$t('admin_dash.emoji.import_pack')"
|
||||
@click="$refs.additionalRemotePopover.showPopover"
|
||||
>
|
||||
<FAIcon icon="folder-open" />
|
||||
{{ $t('admin_dash.emoji.import_pack_short') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<h3>{{ $t('admin_dash.emoji.new_pack_name') }}</h3>
|
||||
|
|
@ -171,94 +78,276 @@
|
|||
:placeholder="$t('admin_dash.emoji.new_pack_name')"
|
||||
class="input"
|
||||
>
|
||||
<h3>Import pack from URL</h3>
|
||||
<input
|
||||
v-model="remotePackURL"
|
||||
class="input"
|
||||
placeholder="Pack .zip URL"
|
||||
>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="createEmojiPack"
|
||||
:disabled="newPackName.trim() === '' || remotePackURL.trim() === ''"
|
||||
@click="downloadRemoteURLPack"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.create') }}
|
||||
Import
|
||||
</button>
|
||||
<h3>Import pack from a file</h3>
|
||||
<input
|
||||
type="file"
|
||||
accept="application/zip"
|
||||
class="emoji-tab-popover-file input"
|
||||
@change="remotePackFile = $event.target.files"
|
||||
>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
:disabled="newPackName.trim() === '' || remotePackFile === null || remotePackFile.length === 0"
|
||||
@click="downloadRemoteFilePack"
|
||||
>
|
||||
Import
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</h3>
|
||||
<div class="setting-section">
|
||||
<h4 class="toolbar">
|
||||
{{ $t('admin_dash.emoji.edit_pack') }}
|
||||
</h4>
|
||||
<div class="setting-item selector-buttons">
|
||||
<button
|
||||
:disabled="!pack || pack.remote !== undefined"
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="deleteModalVisible = true"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.delete_pack') }}
|
||||
|
||||
<div v-if="pack">
|
||||
<div class="pack-info-wrapper">
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.description') }}
|
||||
<ConfirmModal
|
||||
v-if="deleteModalVisible"
|
||||
:title="$t('admin_dash.emoji.delete_title')"
|
||||
:cancel-text="$t('status.delete_confirm_cancel_button')"
|
||||
:confirm-text="$t('status.delete_confirm_accept_button')"
|
||||
@cancelled="deleteModalVisible = false"
|
||||
@accepted="deleteEmojiPack"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.delete_confirm', [packName]) }}
|
||||
</ConfirmModal>
|
||||
</button>
|
||||
|
||||
<button
|
||||
:disabled="!pack || pack.remote === undefined"
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="$refs.downloadPackPopover.showPopover"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.download_pack') }}
|
||||
|
||||
<Popover
|
||||
ref="downloadPackPopover"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
>
|
||||
<template #content>
|
||||
<h3>{{ $t('admin_dash.emoji.downloading_pack', [packName]) }}</h3>
|
||||
<div>
|
||||
<div>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.download_as_name') }}
|
||||
<input
|
||||
v-model="remotePackDownloadAs"
|
||||
class="emoji-data-input input"
|
||||
:placeholder="$t('admin_dash.emoji.download_as_name_full')"
|
||||
>
|
||||
</label>
|
||||
|
||||
<div
|
||||
v-if="downloadWillReplaceLocal"
|
||||
class="warning"
|
||||
>
|
||||
<em>{{ $t('admin_dash.emoji.replace_warning') }}</em>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="downloadRemotePack"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.download') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</button>
|
||||
|
||||
<span class="btn-group">
|
||||
<Select
|
||||
v-model="packName"
|
||||
class="form-control"
|
||||
>
|
||||
<option
|
||||
value=""
|
||||
disabled
|
||||
hidden
|
||||
>
|
||||
{{ $t('admin_dash.emoji.emoji_pack') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="(pack, listPackName) in knownPacks"
|
||||
:key="listPackName"
|
||||
:label="listPackName"
|
||||
>
|
||||
{{ listPackName }}
|
||||
</option>
|
||||
</Select>
|
||||
|
||||
<Popover
|
||||
ref="createPackPopover"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
>
|
||||
<template #trigger>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.create_pack') }}
|
||||
</button>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<h3>{{ $t('admin_dash.emoji.new_pack_name') }}</h3>
|
||||
<input
|
||||
v-model="newPackName"
|
||||
:placeholder="$t('admin_dash.emoji.new_pack_name')"
|
||||
class="input"
|
||||
>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="createEmojiPack"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.create') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</span>
|
||||
</div>
|
||||
<h5>
|
||||
{{ $t('admin_dash.emoji.metadata') }}
|
||||
|
||||
<ModifiedIndicator
|
||||
:changed="$refs.emojiPopovers && $refs.emojiPopovers.some(p => p.isEdited)"
|
||||
message-key="admin_dash.emoji.emoji_changed"
|
||||
/>
|
||||
</h5>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<label
|
||||
class="setting-item"
|
||||
:class="{ ['-disabled']: !pack || pack.remote !== undefined }"
|
||||
>
|
||||
<span class="setting-label">
|
||||
<ModifiedIndicator
|
||||
:changed="metaEdited('description')"
|
||||
message-key="admin_dash.emoji.metadata_changed"
|
||||
/>
|
||||
|
||||
<textarea
|
||||
v-model="packMeta.description"
|
||||
:disabled="pack.remote !== undefined"
|
||||
class="bio resize-height input"
|
||||
/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.homepage') }}
|
||||
{{ $t('admin_dash.emoji.description') }}
|
||||
</span>
|
||||
<textarea
|
||||
v-model="packMeta.description"
|
||||
:disabled="!pack || pack.remote !== undefined"
|
||||
height="4"
|
||||
class="bio resize-height input textarea setting-control"
|
||||
/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label
|
||||
class="setting-item"
|
||||
:class="{ ['-disabled']: !pack || pack.remote !== undefined }"
|
||||
>
|
||||
<span class="setting-label">
|
||||
<ModifiedIndicator
|
||||
:changed="metaEdited('homepage')"
|
||||
message-key="admin_dash.emoji.metadata_changed"
|
||||
/>
|
||||
{{ $t('admin_dash.emoji.homepage') }}
|
||||
</span>
|
||||
|
||||
<input
|
||||
v-model="packMeta.homepage"
|
||||
class="emoji-info-input input"
|
||||
:disabled="pack.remote !== undefined"
|
||||
>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.fallback_src') }}
|
||||
<input
|
||||
v-model="packMeta.homepage"
|
||||
class="emoji-info-input input setting-control"
|
||||
:disabled="!pack || pack.remote !== undefined"
|
||||
>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label
|
||||
class="setting-item"
|
||||
:class="{ ['-disabled']: !pack || pack.remote !== undefined }"
|
||||
>
|
||||
<span class="setting-label">
|
||||
<ModifiedIndicator
|
||||
:changed="metaEdited('fallback-src')"
|
||||
message-key="admin_dash.emoji.metadata_changed"
|
||||
/>
|
||||
{{ $t('admin_dash.emoji.fallback_src') }}
|
||||
</span>
|
||||
|
||||
<input
|
||||
v-model="packMeta['fallback-src']"
|
||||
class="emoji-info-input input"
|
||||
:disabled="pack.remote !== undefined"
|
||||
>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label>
|
||||
<input
|
||||
v-model="packMeta['fallback-src']"
|
||||
class="emoji-info-input input setting-control"
|
||||
:disabled="!pack || pack.remote !== undefined"
|
||||
>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label
|
||||
class="setting-item"
|
||||
:class="{ ['-disabled']: !pack || pack.remote !== undefined }"
|
||||
>
|
||||
<span class="setting-label">
|
||||
{{ $t('admin_dash.emoji.fallback_sha256') }}
|
||||
</span>
|
||||
|
||||
<input
|
||||
v-model="packMeta['fallback-src-sha256']"
|
||||
:disabled="true"
|
||||
class="emoji-info-input input"
|
||||
>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
v-model="packMeta['fallback-src-sha256']"
|
||||
:disabled="!pack || pack.remote !== undefined"
|
||||
class="emoji-info-input input setting-control"
|
||||
>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<div class="setting-item">
|
||||
<Checkbox
|
||||
v-model="packMeta['share-files']"
|
||||
:disabled="pack.remote !== undefined"
|
||||
:disabled="!pack || pack.remote !== undefined"
|
||||
class="setting-label setting-control"
|
||||
>
|
||||
<ModifiedIndicator
|
||||
:changed="metaEdited('share-files')"
|
||||
message-key="admin_dash.emoji.metadata_changed"
|
||||
/>
|
||||
{{ $t('admin_dash.emoji.share') }}
|
||||
</Checkbox>
|
||||
|
||||
<ModifiedIndicator
|
||||
:changed="metaEdited('share-files')"
|
||||
message-key="admin_dash.emoji.metadata_changed"
|
||||
/>
|
||||
</li>
|
||||
<li class="btn-group">
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="meta-buttons">
|
||||
<button
|
||||
v-if="pack.remote === undefined"
|
||||
v-if="pack && pack.remote === undefined"
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="savePackMetadata"
|
||||
|
|
@ -266,148 +355,89 @@
|
|||
{{ $t('admin_dash.emoji.save_meta') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="pack.remote === undefined"
|
||||
v-if="pack && pack.remote === undefined"
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="savePackMetadata"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.revert_meta') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="pack.remote === undefined"
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="deleteModalVisible = true"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.delete_pack') }}
|
||||
|
||||
<ConfirmModal
|
||||
v-if="deleteModalVisible"
|
||||
:title="$t('admin_dash.emoji.delete_title')"
|
||||
:cancel-text="$t('status.delete_confirm_cancel_button')"
|
||||
:confirm-text="$t('status.delete_confirm_accept_button')"
|
||||
@cancelled="deleteModalVisible = false"
|
||||
@accepted="deleteEmojiPack"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.delete_confirm', [packName]) }}
|
||||
</ConfirmModal>
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="pack.remote !== undefined"
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="$refs.downloadPackPopover.showPopover"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.download_pack') }}
|
||||
|
||||
<Popover
|
||||
ref="downloadPackPopover"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
>
|
||||
<template #content>
|
||||
<h3>{{ $t('admin_dash.emoji.downloading_pack', [packName]) }}</h3>
|
||||
<div>
|
||||
<div>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.download_as_name') }}
|
||||
<input
|
||||
v-model="remotePackDownloadAs"
|
||||
class="emoji-data-input input"
|
||||
:placeholder="$t('admin_dash.emoji.download_as_name_full')"
|
||||
>
|
||||
</label>
|
||||
|
||||
<div
|
||||
v-if="downloadWillReplaceLocal"
|
||||
class="warning"
|
||||
>
|
||||
<em>{{ $t('admin_dash.emoji.replace_warning') }}</em>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="downloadRemotePack"
|
||||
>
|
||||
{{ $t('admin_dash.emoji.download') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ul class="setting-list">
|
||||
<h4>
|
||||
{{ $t('admin_dash.emoji.files') }}
|
||||
|
||||
<ModifiedIndicator
|
||||
v-if="pack"
|
||||
:changed="$refs.emojiPopovers && $refs.emojiPopovers.some(p => p.isEdited)"
|
||||
message-key="admin_dash.emoji.emoji_changed"
|
||||
/>
|
||||
</h4>
|
||||
|
||||
<div
|
||||
v-if="pack"
|
||||
class="emoji-list"
|
||||
>
|
||||
<EmojiEditingPopover
|
||||
v-if="pack.remote === undefined"
|
||||
placement="bottom"
|
||||
new-upload
|
||||
:title="$t('admin_dash.emoji.adding_new')"
|
||||
:pack-name="packName"
|
||||
@update-pack-files="updatePackFiles"
|
||||
@display-error="displayError"
|
||||
>
|
||||
<template #trigger>
|
||||
<FAIcon
|
||||
icon="plus"
|
||||
size="2x"
|
||||
:title="$t('admin_dash.emoji.add_file')"
|
||||
/>
|
||||
</template>
|
||||
</EmojiEditingPopover>
|
||||
|
||||
<EmojiEditingPopover
|
||||
v-for="(file, shortcode) in pack.files"
|
||||
ref="emojiPopovers"
|
||||
:key="shortcode"
|
||||
placement="top"
|
||||
:title="$t(`admin_dash.emoji.${pack.remote === undefined ? 'editing' : 'copying'}`, [shortcode])"
|
||||
:shortcode="shortcode"
|
||||
:file="file"
|
||||
:pack-name="packName"
|
||||
:remote="pack.remote"
|
||||
:known-local-packs="knownLocalPacks"
|
||||
@update-pack-files="updatePackFiles"
|
||||
@display-error="displayError"
|
||||
>
|
||||
<template #trigger>
|
||||
<StillImage
|
||||
class="emoji"
|
||||
:src="emojiAddr(file)"
|
||||
:title="`:${shortcode}:`"
|
||||
:alt="`:${shortcode}:`"
|
||||
/>
|
||||
</template>
|
||||
</EmojiEditingPopover>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<h5>
|
||||
{{ $t('admin_dash.emoji.files') }}
|
||||
|
||||
<ModifiedIndicator
|
||||
:changed="$refs.emojiPopovers && $refs.emojiPopovers.some(p => p.isEdited)"
|
||||
message-key="admin_dash.emoji.emoji_changed"
|
||||
/>
|
||||
</h5>
|
||||
|
||||
<div
|
||||
class="emoji-list setting-list"
|
||||
>
|
||||
<EmojiEditingPopover
|
||||
v-if="pack && pack.remote === undefined"
|
||||
class="emoji-item"
|
||||
placement="bottom"
|
||||
new-upload
|
||||
:title="$t('admin_dash.emoji.adding_new')"
|
||||
:pack-name="packName"
|
||||
@update-pack-files="updatePackFiles"
|
||||
@display-error="displayError"
|
||||
>
|
||||
<template #trigger>
|
||||
<FAIcon
|
||||
icon="plus"
|
||||
size="2x"
|
||||
:title="$t('admin_dash.emoji.add_file')"
|
||||
/>
|
||||
</template>
|
||||
</EmojiEditingPopover>
|
||||
<template v-if="!pack">
|
||||
<div
|
||||
v-for="(_, i) in new Array(20)"
|
||||
:key="i"
|
||||
class="placeholder"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
||||
<EmojiEditingPopover
|
||||
v-for="(file, shortcode) in (pack?.files || [])"
|
||||
ref="emojiPopovers"
|
||||
:key="shortcode"
|
||||
placement="top"
|
||||
:title="$t(`admin_dash.emoji.${pack?.remote === undefined ? 'editing' : 'copying'}`, [shortcode])"
|
||||
:shortcode="shortcode"
|
||||
:file="file"
|
||||
:pack-name="packName"
|
||||
:remote="pack?.remote"
|
||||
:known-local-packs="knownLocalPacks"
|
||||
@update-pack-files="updatePackFiles"
|
||||
@display-error="displayError"
|
||||
>
|
||||
<template #trigger>
|
||||
<StillImage
|
||||
class="emoji"
|
||||
:src="emojiAddr(file)"
|
||||
:title="`:${shortcode}:`"
|
||||
:alt="`:${shortcode}:`"
|
||||
/>
|
||||
</template>
|
||||
</EmojiEditingPopover>
|
||||
</div>
|
||||
</div>
|
||||
<h3>{{ $t('admin_dash.emoji.advanced') }}</h3>
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
@click="importFromFS"
|
||||
>
|
||||
<FAIcon icon="server" />
|
||||
{{ $t('admin_dash.emoji.importFS') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
34
src/components/settings_modal/admin_tabs/federation_tab.js
Normal file
34
src/components/settings_modal/admin_tabs/federation_tab.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
import ListTupleSetting from '../helpers/list_tuple_setting.vue'
|
||||
import MapSetting from '../helpers/map_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const FederationTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
AttachmentSetting,
|
||||
ListSetting,
|
||||
ListTupleSetting,
|
||||
GroupSetting,
|
||||
MapSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
export default FederationTab
|
||||
68
src/components/settings_modal/admin_tabs/federation_tab.vue
Normal file
68
src/components/settings_modal/admin_tabs/federation_tab.vue
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.federation')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.federation.global') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:federating" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:skip_thread_containment" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:external_user_synchronization" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.federation.restrictions') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<MapSetting path=":pleroma.:instance.:quarantined_instances" />
|
||||
</li>
|
||||
<li>
|
||||
<MapSetting path=":pleroma.:instance.:rejected_instances" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.federation.activitypub') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:allow_relay" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:activitypub.:unfollow_blocked" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:activitypub.:outgoing_blocks" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:activitypub.:blockers_visible" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:activitypub.:follow_handshake_timeout" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:activitypub.:note_replies_output_limit" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:instance.:federation_incoming_replies_max_depth" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:instance.:federation_reachability_timeout_days" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:allow_relay" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:activitypub.:sign_object_fetches" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:activitypub.:authorized_fetch_mode" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:activitypub.:client_api_enabled" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./federation_tab.js"></script>
|
||||
|
|
@ -44,10 +44,10 @@ const FrontendsTab = {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject(),
|
||||
frontends () {
|
||||
return this.$store.state.adminSettings.frontends
|
||||
},
|
||||
...SharedComputedObject()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
canInstall (frontend) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,24 @@
|
|||
.frontends-tab {
|
||||
.FrontendsTab {
|
||||
.cards-list {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li.frontend-card {
|
||||
display: flex;
|
||||
margin: 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.frontend-buttons {
|
||||
margin-top: 0.5em;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
gap: 0.5em;
|
||||
flex-wrap: wrap;
|
||||
flex: 1 0 auto;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
|
@ -16,10 +32,26 @@
|
|||
inset: 0;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
font-size: 1.15em
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin-top: 0.5em;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
dd {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
max-width: 10em;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<div
|
||||
class="frontends-tab"
|
||||
class="FrontendsTab"
|
||||
:label="$t('admin_dash.tabs.frontends')"
|
||||
>
|
||||
<div class="setting-item">
|
||||
<h2>{{ $t('admin_dash.tabs.frontends') }}</h2>
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.frontend.title') }}</h3>
|
||||
<p>{{ $t('admin_dash.frontend.wip_notice') }}</p>
|
||||
<ul
|
||||
v-if="adminDraft"
|
||||
class="setting-list"
|
||||
>
|
||||
<li>
|
||||
<h3>{{ $t('admin_dash.frontend.default_frontend') }}</h3>
|
||||
<h4>{{ $t('admin_dash.frontend.default_frontend') }}</h4>
|
||||
<p>{{ $t('admin_dash.frontend.default_frontend_tip') }}</p>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
|
|
@ -38,13 +38,14 @@
|
|||
v-if="working"
|
||||
class="overlay"
|
||||
/>
|
||||
<h3>{{ $t('admin_dash.frontend.available_frontends') }}</h3>
|
||||
<h4>{{ $t('admin_dash.frontend.available_frontends') }}</h4>
|
||||
<ul class="cards-list">
|
||||
<li
|
||||
v-for="frontend in frontends"
|
||||
:key="frontend.name"
|
||||
class="frontend-card"
|
||||
>
|
||||
<strong>{{ frontend.name }}</strong>
|
||||
<h5>{{ frontend.name }}</h5>
|
||||
{{ ' ' }}
|
||||
<span v-if="adminDraft && adminDraft[':pleroma'][':frontends'][':primary']?.name === frontend.name">
|
||||
<i18n-t
|
||||
|
|
@ -89,7 +90,7 @@
|
|||
>{{ frontend.build_url }}</a>
|
||||
</dd>
|
||||
</dl>
|
||||
<div>
|
||||
<div class="frontend-buttons">
|
||||
<span class="btn-group">
|
||||
<button
|
||||
class="button button-default btn"
|
||||
|
|
|
|||
46
src/components/settings_modal/admin_tabs/http_tab.js
Normal file
46
src/components/settings_modal/admin_tabs/http_tab.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
import TupleSetting from '../helpers/tuple_setting.vue'
|
||||
import MapSetting from '../helpers/map_setting.vue'
|
||||
import ProxySetting from '../helpers/proxy_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
import { get } from 'lodash'
|
||||
|
||||
const HTTPTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
AttachmentSetting,
|
||||
MapSetting,
|
||||
GroupSetting,
|
||||
ListSetting,
|
||||
TupleSetting,
|
||||
ProxySetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject(),
|
||||
sslOptions () {
|
||||
const desc = get(this.$store.state.adminSettings.descriptions, ':pleroma.:http.:adapter.:ssl_options.:versions')
|
||||
return new Set(desc.suggestions.map(option => ({
|
||||
label: option.replace(':tlsv', 'TLS v'),
|
||||
value: option
|
||||
})))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default HTTPTab
|
||||
86
src/components/settings_modal/admin_tabs/http_tab.vue
Normal file
86
src/components/settings_modal/admin_tabs/http_tab.vue
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<div
|
||||
class="LinksTab"
|
||||
:label="$t('admin_dash.tabs.http')"
|
||||
>
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.http.outbound') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<ProxySetting
|
||||
hide-description
|
||||
path=":pleroma.:http.:proxy_url"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:http.:send_user_agent" />
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:http.:user_agent" />
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
override-available-options
|
||||
:options="sslOptions"
|
||||
path=":pleroma.:http.:adapter.:ssl_options.:versions"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<GroupSetting path=":pleroma.:http.:adapter" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.http.incoming') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<h4>{{ $t('admin_dash.http.security') }}</h4>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:http_security.:enabled" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:http_security.:sts" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:http_security.:sts_max_age" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:http_security.:ct_max_age" />
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:http_security.:referrer_policy" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:http_security.:allow_unsafe_eval" />
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:http_security.:report_url" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.http.web_push') }}</h3>
|
||||
<p>{{ $t('admin_dash.http.web_push_description') }}</p>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<StringSetting
|
||||
path=":web_push_encryption.:vapid_details.:subject"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
path=":web_push_encryption.:vapid_details.:public_key"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
path=":web_push_encryption.:vapid_details.:private_key"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- CONFIRM admin_token should go there but something is wrong with both data and description. -->
|
||||
<!-- given the nature of the setting it's probably better to not expose it and deprecate it on backend side -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!--<style lang="scss" src="./http_tab.scss"></style>-->
|
||||
|
||||
<script src="./http_tab.js"></script>
|
||||
|
|
@ -2,18 +2,15 @@ import BooleanSetting from '../helpers/boolean_setting.vue'
|
|||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import ColorSetting from '../helpers/color_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue'
|
||||
import MapSetting from '../helpers/map_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faGlobe
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faGlobe
|
||||
)
|
||||
import { get } from 'lodash'
|
||||
|
||||
const InstanceTab = {
|
||||
provide () {
|
||||
|
|
@ -27,11 +24,29 @@ const InstanceTab = {
|
|||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
ColorSetting,
|
||||
AttachmentSetting,
|
||||
ListSetting,
|
||||
PWAManifestIconsSetting,
|
||||
MapSetting,
|
||||
GroupSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject()
|
||||
...SharedComputedObject(),
|
||||
providersOptions () {
|
||||
const desc = get(this.$store.state.adminSettings.descriptions, [':pleroma', 'Pleroma.Web.Metadata', ':providers'])
|
||||
return new Set(desc.suggestions.map(option => ({
|
||||
label: option.replace('Pleroma.Web.Metadata.Providers.', ''),
|
||||
value: option
|
||||
})))
|
||||
},
|
||||
limitLocalContentOptions () {
|
||||
const desc = get(this.$store.state.adminSettings.descriptions, [':pleroma', ':instance', ':limit_to_local_content'])
|
||||
return new Set(desc.suggestions.map(option => ({
|
||||
label: option !== 'false' ? this.$t('admin_dash.instance.' + option) : this.$t('general.no'),
|
||||
value: option
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.instance')">
|
||||
<div class="setting-item">
|
||||
<h2>{{ $t('admin_dash.instance.instance') }}</h2>
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.instance.instance') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:instance.:name" />
|
||||
</li>
|
||||
<!-- See https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3963 -->
|
||||
<li v-if="adminDraft[':pleroma'][':instance'][':favicon'] !== undefined">
|
||||
<AttachmentSetting
|
||||
compact
|
||||
path=":pleroma.:instance.:favicon"
|
||||
/>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:instance.:contact_username" />
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:instance.:email" />
|
||||
|
|
@ -22,87 +18,68 @@
|
|||
<li>
|
||||
<StringSetting path=":pleroma.:instance.:short_description" />
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
force-new
|
||||
ignore-suggestions
|
||||
path=":pleroma.:instance.:languages"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:instance.:status_page" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.instance.branding') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<!-- See https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3963 -->
|
||||
<li v-if="adminDraft[':pleroma'][':instance'][':favicon'] !== undefined">
|
||||
<AttachmentSetting
|
||||
compact
|
||||
path=":pleroma.:instance.:favicon"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<AttachmentSetting
|
||||
compact
|
||||
path=":pleroma.:instance.:instance_thumbnail"
|
||||
/>
|
||||
</li>
|
||||
<h4>{{ $t('admin_dash.instance.pwa.manifest') }}</H4>
|
||||
<li>
|
||||
<PWAManifestIconsSetting path=":pleroma.:manifest.:icons" />
|
||||
</li>
|
||||
<li>
|
||||
<ColorSetting hide-draft-buttons path=":pleroma.:manifest.:theme_color" />
|
||||
</li>
|
||||
<li>
|
||||
<ColorSetting hide-draft-buttons path=":pleroma.:manifest.:background_color" />
|
||||
</li>
|
||||
<li>
|
||||
<GroupSetting path=":pleroma.:manifest" />
|
||||
</li>
|
||||
<h4>{{ $t('admin_dash.instance.misc_brand') }}</H4>
|
||||
<li>
|
||||
<AttachmentSetting path=":pleroma.:instance.:background_image" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<h2>{{ $t('admin_dash.instance.registrations') }}</h2>
|
||||
<h3>{{ $t('admin_dash.instance.rich_metadata') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:registrations_open" />
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path=":pleroma.:instance.:invites_enabled"
|
||||
parent-path=":pleroma.:instance.:registrations_open"
|
||||
parent-invert
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ListSetting
|
||||
override-available-options
|
||||
:options="providersOptions"
|
||||
:path="[':pleroma','Pleroma.Web.Metadata', ':providers']"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:birthday_required" />
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
path=":pleroma.:instance.:birthday_min_age"
|
||||
parent-path=":pleroma.:instance.:birthday_required"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:account_activation_required" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:account_approval_required" />
|
||||
</li>
|
||||
<li>
|
||||
<h3>{{ $t('admin_dash.instance.captcha_header') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting :path="[':pleroma', 'Pleroma.Captcha', ':enabled']" />
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<ChoiceSetting
|
||||
:path="[':pleroma', 'Pleroma.Captcha', ':method']"
|
||||
:parent-path="[':pleroma', 'Pleroma.Captcha', ':enabled']"
|
||||
:option-label-map="{
|
||||
'Pleroma.Captcha.Native': $t('admin_dash.captcha.native'),
|
||||
'Pleroma.Captcha.Kocaptcha': $t('admin_dash.captcha.kocaptcha')
|
||||
}"
|
||||
/>
|
||||
<IntegerSetting
|
||||
:path="[':pleroma', 'Pleroma.Captcha', ':seconds_valid']"
|
||||
:parent-path="[':pleroma', 'Pleroma.Captcha', ':enabled']"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
v-if="adminDraft[':pleroma']['Pleroma.Captcha'][':enabled'] && adminDraft[':pleroma']['Pleroma.Captcha'][':method'] === 'Pleroma.Captcha.Kocaptcha'"
|
||||
>
|
||||
<h4>{{ $t('admin_dash.instance.kocaptcha') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<StringSetting :path="[':pleroma', 'Pleroma.Captcha.Kocaptcha', ':endpoint']" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<BooleanSetting
|
||||
:path="[':pleroma','Pleroma.Web.Metadata', ':unfurl_nsfw']"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<h2>{{ $t('admin_dash.instance.access') }}</h2>
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.instance.access') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting
|
||||
|
|
@ -115,6 +92,8 @@
|
|||
<ChoiceSetting
|
||||
override-backend-description
|
||||
override-backend-description-label
|
||||
override-available-options
|
||||
:options="limitLocalContentOptions"
|
||||
path=":pleroma.:instance.:limit_to_local_content"
|
||||
/>
|
||||
</li>
|
||||
|
|
|
|||
34
src/components/settings_modal/admin_tabs/job_queues_tab.js
Normal file
34
src/components/settings_modal/admin_tabs/job_queues_tab.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import TupleSetting from '../helpers/tuple_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const JobQueuesTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
TupleSetting,
|
||||
AttachmentSetting,
|
||||
GroupSetting,
|
||||
ListSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
export default JobQueuesTab
|
||||
157
src/components/settings_modal/admin_tabs/job_queues_tab.vue
Normal file
157
src/components/settings_modal/admin_tabs/job_queues_tab.vue
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.job_queues')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.job_queues.Gun.title') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.job_queues.Gun.connections_pools') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:connections_pool.:connect_timeout" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:connections_pool.:connection_acquisition_retries" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:connections_pool.:connection_acquisition_wait" />
|
||||
</li>
|
||||
<li>
|
||||
<!-- CONFIRM what is this -->
|
||||
<IntegerSetting path=":pleroma.:connections_pool.:retry" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:connections_pool.:max_connections" />
|
||||
</li>
|
||||
<li>
|
||||
<!-- CONFIRM what is this -->
|
||||
<IntegerSetting path=":pleroma.:connections_pool.:max_idle_time" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:connections_pool.:reclaim_multiplier" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.job_queues.Gun.pools.title') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<h5>{{ $t('admin_dash.job_queues.Gun.pools.default') }}</h5>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:default.:size" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:default.:max_waiting" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:default.:recv_timeout" />
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:pools.:default" />
|
||||
</li>
|
||||
<li>
|
||||
<h5>{{ $t('admin_dash.job_queues.Gun.pools.federation') }}</h5>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:federation.:size" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:federation.:max_waiting" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:federation.:recv_timeout" />
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:pools.:federation" />
|
||||
</li>
|
||||
<li>
|
||||
<!-- CONFIRM what is this? -->
|
||||
<h5>{{ $t('admin_dash.job_queues.Gun.pools.rich_media') }}</h5>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:rich_media.:size" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:rich_media.:max_waiting" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:rich_media.:recv_timeout" />
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:pools.:rich_media" />
|
||||
</li>
|
||||
<li>
|
||||
<h5>{{ $t('admin_dash.job_queues.Gun.pools.media') }}</h5>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:media.:size" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:media.:max_waiting" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:pools.:media.:recv_timeout" />
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:pools.:media" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.job_queues.Hackney.title') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.job_queues.Hackney.federation') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:hackney_pools.:federation.:max_connections" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:hackney_pools.:federation.:timeout" />
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:hackney_pools.:federation" />
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.job_queues.Hackney.media') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:hackney_pools.:media.:max_connections" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:hackney_pools.:media.:timeout" />
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:hackney_pools.:media" />
|
||||
</li>
|
||||
<li>
|
||||
<!-- CONFIRM what is this -->
|
||||
<h4>{{ $t('admin_dash.job_queues.Hackney.rich_media') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:hackney_pools.:rich_media.:max_connections" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:hackney_pools.:rich_media.:timeout" />
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:hackney_pools.:rich_media" />
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.job_queues.Hackney.upload') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:hackney_pools.:upload.:max_connections" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:hackney_pools.:upload.:timeout" />
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:hackney_pools.:upload" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./job_queues_tab.js"></script>
|
||||
|
|
@ -4,14 +4,6 @@ import IntegerSetting from '../helpers/integer_setting.vue'
|
|||
import StringSetting from '../helpers/string_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faGlobe
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faGlobe
|
||||
)
|
||||
|
||||
const LimitsTab = {
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.limits')">
|
||||
<div class="setting-item">
|
||||
<h2>{{ $t('admin_dash.limits.arbitrary_limits') }}</h2>
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.limits.arbitrary_limits') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<h3>{{ $t('admin_dash.limits.posts') }}</h3>
|
||||
<h4>{{ $t('admin_dash.limits.posts') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h3>{{ $t('admin_dash.limits.uploads') }}</h3>
|
||||
<h4>{{ $t('admin_dash.limits.uploads') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h3>{{ $t('admin_dash.limits.users') }}</h3>
|
||||
<h4>{{ $t('admin_dash.limits.users') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
/>
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.limits.profile_fields') }}</h4>
|
||||
<h5>{{ $t('admin_dash.limits.profile_fields') }}</h5>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.limits.user_uploads') }}</h4>
|
||||
<h5>{{ $t('admin_dash.limits.user_uploads') }}</h5>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
|
|
@ -128,6 +128,25 @@
|
|||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.limits.other') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
source="admin"
|
||||
path=":pleroma.:instance.:max_report_comment_size"
|
||||
draft-mode
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting
|
||||
source="admin"
|
||||
path=":pleroma.:instance.:max_endorsed_users"
|
||||
draft-mode
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
109
src/components/settings_modal/admin_tabs/links_tab.js
Normal file
109
src/components/settings_modal/admin_tabs/links_tab.js
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
import { get } from 'lodash'
|
||||
|
||||
const LinksTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
AttachmentSetting,
|
||||
GroupSetting,
|
||||
ListSetting,
|
||||
Checkbox
|
||||
},
|
||||
computed: {
|
||||
classIsPresent () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':class'] !== false
|
||||
},
|
||||
relIsPresent () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':rel'] !== false
|
||||
},
|
||||
truncateIsPresent () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':truncate'] !== false
|
||||
},
|
||||
truncateDescription () {
|
||||
return get(this.$store.state.adminSettings.descriptions, [':pleroma', 'Pleroma.Formatter', ':truncate'])
|
||||
},
|
||||
ttlSettersOptions () {
|
||||
const desc = get(this.$store.state.adminSettings.descriptions, ':pleroma.:rich_media.:ttl_setters')
|
||||
return new Set(desc.suggestions.map(option => ({
|
||||
label: option.replace('Pleroma.Web.RichMedia.Parser.TTL.', ''),
|
||||
value: option
|
||||
})))
|
||||
},
|
||||
parsersOptions () {
|
||||
const desc = get(this.$store.state.adminSettings.descriptions, ':pleroma.:rich_media.:parsers')
|
||||
return new Set(desc.suggestions.map(option => ({
|
||||
label: option.replace('Pleroma.Web.RichMedia.Parsers.', ''),
|
||||
value: option
|
||||
})))
|
||||
},
|
||||
validateTLDOptions () {
|
||||
return [{
|
||||
label: this.$t('general.yes'),
|
||||
value: true
|
||||
}, {
|
||||
label: this.$t('general.no'),
|
||||
value: false
|
||||
}, {
|
||||
label: this.$t('admin_dash.links.no_scheme'),
|
||||
value: ':no_scheme'
|
||||
}]
|
||||
},
|
||||
mediaProxyEnabled () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':enabled']
|
||||
},
|
||||
mediaInvalidationProvider () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':invalidation'][':provider']
|
||||
},
|
||||
...SharedComputedObject()
|
||||
},
|
||||
methods: {
|
||||
checkRel (e) {
|
||||
this.$store.commit(
|
||||
'updateAdminDraft',
|
||||
{
|
||||
path: [':pleroma','Pleroma.Formatter',':rel'],
|
||||
value: e ? '' : false
|
||||
}
|
||||
)
|
||||
},
|
||||
checkClass (e) {
|
||||
this.$store.commit(
|
||||
'updateAdminDraft',
|
||||
{
|
||||
path: [':pleroma','Pleroma.Formatter',':class'],
|
||||
value: e ? '' : false
|
||||
}
|
||||
)
|
||||
},
|
||||
checkTruncate (e) {
|
||||
this.$store.commit(
|
||||
'updateAdminDraft',
|
||||
{
|
||||
path: [':pleroma','Pleroma.Formatter',':truncate'],
|
||||
value: e ? 20 : false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default LinksTab
|
||||
45
src/components/settings_modal/admin_tabs/links_tab.vue
Normal file
45
src/components/settings_modal/admin_tabs/links_tab.vue
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div
|
||||
class="LinksTab"
|
||||
:label="$t('admin_dash.tabs.media_proxy')"
|
||||
>
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.links.link_previews') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:rich_media.:enabled" />
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
override-available-options
|
||||
:options="parsersOptions"
|
||||
path=":pleroma.:rich_media.:parsers"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting
|
||||
path=":pleroma.:rich_media.:timeout"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
override-available-options
|
||||
:options="ttlSettersOptions"
|
||||
path=":pleroma.:rich_media.:ttl_setters"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
path=":pleroma.:rich_media.:ignore_tld"
|
||||
ignore-suggestions
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting path=":pleroma.:rich_media.:ignore_hosts" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./links_tab.js"></script>
|
||||
65
src/components/settings_modal/admin_tabs/mailer_tab.js
Normal file
65
src/components/settings_modal/admin_tabs/mailer_tab.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import ColorSetting from '../helpers/color_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const MailerTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
AttachmentSetting,
|
||||
ColorSetting,
|
||||
GroupSetting
|
||||
},
|
||||
computed: {
|
||||
adaptersLabels () {
|
||||
const prefix = 'Swoosh.Adapters.'
|
||||
const descriptions = this.$store.state.adminSettings.descriptions
|
||||
const options = descriptions[':pleroma']['Pleroma.Emails.Mailer'][':adapter'].suggestions
|
||||
|
||||
return Object.fromEntries(options.map(value => [
|
||||
value, value.replace(prefix, '')
|
||||
]))
|
||||
},
|
||||
startTLSLabels () {
|
||||
return {
|
||||
':always': this.$t('admin_dash.generic_enforcement.always'),
|
||||
':if_available': this.$t('admin_dash.generic_enforcement.if_available'),
|
||||
':never': this.$t('admin_dash.generic_enforcement.never')
|
||||
}
|
||||
// return Object.fromEntries(options.map(value => [
|
||||
// value, value.replace(prefix, '')
|
||||
// ]))
|
||||
},
|
||||
adapter () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Emails.Mailer'][':adapter']
|
||||
},
|
||||
mailerEnabled () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Emails.Mailer'][':enabled']
|
||||
},
|
||||
...SharedComputedObject()
|
||||
},
|
||||
methods: {
|
||||
adapterHasKey (key) {
|
||||
const descriptions = this.$store.state.adminSettings.descriptions
|
||||
const mailerStuff = descriptions[':pleroma']['Pleroma.Emails.Mailer']
|
||||
const adapterStuff = mailerStuff[':subgroup,' + this.adapter]
|
||||
return Object.prototype.hasOwnProperty.call(adapterStuff, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MailerTab
|
||||
179
src/components/settings_modal/admin_tabs/mailer_tab.vue
Normal file
179
src/components/settings_modal/admin_tabs/mailer_tab.vue
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.mailer')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.mailer.styling') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<h4>{{ $t('admin_dash.mailer.assets') }}</h4>
|
||||
<li>
|
||||
<StringSetting :path="[':pleroma','Pleroma.Emails.UserEmail', ':logo']" />
|
||||
</li>
|
||||
<h4>{{ $t('admin_dash.mailer.colors') }}</h4>
|
||||
<li>
|
||||
<ColorSetting :path="[':pleroma','Pleroma.Emails.UserEmail', ':styling', ':background_color']" />
|
||||
</li>
|
||||
<li>
|
||||
<ColorSetting :path="[':pleroma','Pleroma.Emails.UserEmail', ':styling', ':content_background_color']" />
|
||||
</li>
|
||||
<li>
|
||||
<ColorSetting :path="[':pleroma','Pleroma.Emails.UserEmail', ':styling', ':header_color']" />
|
||||
</li>
|
||||
<li>
|
||||
<ColorSetting :path="[':pleroma','Pleroma.Emails.UserEmail', ':styling', ':text_color']" />
|
||||
</li>
|
||||
<li>
|
||||
<ColorSetting :path="[':pleroma','Pleroma.Emails.UserEmail', ':styling', ':link_color']" />
|
||||
</li>
|
||||
<li>
|
||||
<ColorSetting :path="[':pleroma','Pleroma.Emails.UserEmail', ':styling', ':text_muted_color']" />
|
||||
</li>
|
||||
<li>
|
||||
<GroupSetting :path="[':pleroma','Pleroma.Emails.UserEmail', ':styling']" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.mailer.adapter') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting :path="[':pleroma','Pleroma.Emails.Mailer',':enabled']" />
|
||||
</li>
|
||||
<template v-if="mailerEnabled">
|
||||
<li>
|
||||
<ChoiceSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':adapter']"
|
||||
:option-label-map="adaptersLabels"
|
||||
/>
|
||||
<h4>{{ $t('admin_dash.mailer.auth') }}</h4>
|
||||
<ul class="setting-list suboptions">
|
||||
<li v-if="adapterHasKey(':api_key')">
|
||||
<!-- authentication info -->
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':api_key']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':access_key')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':access_key']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':access_token')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':access_token']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':username')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':username']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':password')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':password']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':secret')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':secret']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':auth')">
|
||||
<ChoiceSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':auth']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<!-- server info -->
|
||||
<li v-if="adapterHasKey(':relay')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':relay']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':ssl')">
|
||||
<BooleanSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':ssl']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':tls')">
|
||||
<ChoiceSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':tls']"
|
||||
:option-label-map="startTLSLabels"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':port')">
|
||||
<IntegerSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':port']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':server_id')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':server_id']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':region')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':region']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':domain')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':domain']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<!-- sendmail exclusive -->
|
||||
<li v-if="adapterHasKey(':cmd_path')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':cmd_path']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':cmd_args')">
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':cmd_args']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':qmail')">
|
||||
<BooleanSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':qmail']"
|
||||
:password="true"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="adapterHasKey(':retries')">
|
||||
<IntegerSetting
|
||||
:path="[':pleroma','Pleroma.Emails.Mailer',':retries']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./mailer_tab.js"></script>
|
||||
38
src/components/settings_modal/admin_tabs/media_proxy_tab.js
Normal file
38
src/components/settings_modal/admin_tabs/media_proxy_tab.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const MediaProxyTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
AttachmentSetting,
|
||||
GroupSetting,
|
||||
ListSetting
|
||||
},
|
||||
computed: {
|
||||
mediaProxyEnabled () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':enabled']
|
||||
},
|
||||
mediaInvalidationProvider () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':invalidation'][':provider']
|
||||
},
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
export default MediaProxyTab
|
||||
135
src/components/settings_modal/admin_tabs/media_proxy_tab.vue
Normal file
135
src/components/settings_modal/admin_tabs/media_proxy_tab.vue
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.media_proxy')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.media_proxy.basic') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:media_proxy.:enabled" />
|
||||
<ul
|
||||
v-if="mediaProxyEnabled"
|
||||
class="setting-list suboptions"
|
||||
>
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:media_proxy.:base_url" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:media_proxy.:proxy_opts.:redirect_on_failure" />
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
ignore-suggestions
|
||||
path=":pleroma.:media_proxy.:whitelist"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<template v-if="mediaProxyEnabled">
|
||||
<h3>{{ $t('admin_dash.media_proxy.invalidation') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:media_proxy.:invalidation.:enabled" />
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<ChoiceSetting
|
||||
path=":pleroma.:media_proxy.:invalidation.:provider"
|
||||
parent-path=":pleroma.:media_proxy.:invalidation.:enabled"
|
||||
/>
|
||||
</li>
|
||||
<h4>{{ $t('admin_dash.media_proxy.invalidation_settings') }}</h4>
|
||||
<ul class="setting-list suboptions">
|
||||
<template v-if="mediaInvalidationProvider === 'Pleroma.Web.MediaProxy.Invalidation.Http'">
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma', 'Pleroma.Web.MediaProxy.Invalidation.Http', ':method']"
|
||||
parent-path=":pleroma.:media_proxy.:invalidation.:enabled"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
ignore-suggestions
|
||||
:path="[':pleroma', 'Pleroma.Web.MediaProxy.Invalidation.Http', ':headers']"
|
||||
parent-path=":pleroma.:media_proxy.:invalidation.:enabled"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
:path="[':pleroma', 'Pleroma.Web.MediaProxy.Invalidation.Http', ':options']"
|
||||
parent-path=":pleroma.:media_proxy.:invalidation.:enabled"
|
||||
/>
|
||||
</li>
|
||||
</template>
|
||||
<template v-if="mediaInvalidationProvider === 'Pleroma.Web.MediaProxy.Invalidation.Script'">
|
||||
<!-- TODO: you know the drill by now - list component -->
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma', 'Pleroma.Web.MediaProxy.Invalidation.Script', ':script_path']"
|
||||
parent-path=":pleroma.:media_proxy.:invalidation.:enabled"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma', 'Pleroma.Web.MediaProxy.Invalidation.Script', ':url_format']"
|
||||
parent-path=":pleroma.:media_proxy.:invalidation.:enabled"
|
||||
/>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.media_proxy.limits') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
path=":pleroma.:media_proxy.:proxy_opts.:max_body_length"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting
|
||||
path=":pleroma.:media_proxy.:proxy_opts.:max_read_duration"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<GroupSetting path=":pleroma.:media_proxy.:proxy_opts" />
|
||||
</li>
|
||||
</ul>
|
||||
<!-- TODO: add whitelist when we have list component (hehe) -->
|
||||
<h3>{{ $t('admin_dash.media_proxy.thumbnails') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:media_preview_proxy.:enabled" />
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
parent-path=":pleroma.:media_preview_proxy.:enabled"
|
||||
path=":pleroma.:media_preview_proxy.:image_quality"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting
|
||||
parent-path=":pleroma.:media_preview_proxy.:enabled"
|
||||
path=":pleroma.:media_preview_proxy.:min_content_length"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting
|
||||
parent-path=":pleroma.:media_preview_proxy.:enabled"
|
||||
path=":pleroma.:media_preview_proxy.:thumbnail_max_width"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting
|
||||
parent-path=":pleroma.:media_preview_proxy.:enabled"
|
||||
path=":pleroma.:media_preview_proxy.:thumbnail_max_height"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./media_proxy_tab.js"></script>
|
||||
42
src/components/settings_modal/admin_tabs/monitoring_tab.js
Normal file
42
src/components/settings_modal/admin_tabs/monitoring_tab.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faGlobe
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faGlobe
|
||||
)
|
||||
|
||||
const MonitoringTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
AttachmentSetting,
|
||||
GroupSetting,
|
||||
ListSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject()
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
|
||||
export default MonitoringTab
|
||||
47
src/components/settings_modal/admin_tabs/monitoring_tab.vue
Normal file
47
src/components/settings_modal/admin_tabs/monitoring_tab.vue
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.monitoring')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.monitoring.builtins') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting :path="[':pleroma','Pleroma.Emails.NewUsersDigestEmail',':enabled']" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:healthcheck" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.monitoring.prometheus') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting :path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':enabled']" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
:parent-path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':enabled']"
|
||||
:path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':auth']"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
:parent-path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':enabled']"
|
||||
:path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':path']"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ChoiceSetting
|
||||
:parent-path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':enabled']"
|
||||
:path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':format']"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
:parent-path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':enabled']"
|
||||
:path="[':prometheus','Pleroma.Web.Endpoint.MetricsExporter',':ip_whitelist']"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./monitoring_tab.js"></script>
|
||||
38
src/components/settings_modal/admin_tabs/other_tab.js
Normal file
38
src/components/settings_modal/admin_tabs/other_tab.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import ColorSetting from '../helpers/color_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue'
|
||||
import MapSetting from '../helpers/map_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const OtherTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
ColorSetting,
|
||||
AttachmentSetting,
|
||||
ListSetting,
|
||||
PWAManifestIconsSetting,
|
||||
MapSetting,
|
||||
GroupSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
export default OtherTab
|
||||
52
src/components/settings_modal/admin_tabs/other_tab.vue
Normal file
52
src/components/settings_modal/admin_tabs/other_tab.vue
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.other')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.other.uncategorized') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<StringSetting path=":pleroma.:instance.:static_dir" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:profile_directory" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.other.reports') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:report_strip_status" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.other.user_backup') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting :path="[':pleroma','Pleroma.User.Backup',':purge_after_days']" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting :path="[':pleroma','Pleroma.User.Backup',':limit_days']" />
|
||||
</li>
|
||||
<!-- CONFIRM what is this?
|
||||
<li>
|
||||
<StringSetting :path="[':pleroma','Pleroma.User.Backup',':dir']" />
|
||||
</li>
|
||||
-->
|
||||
<li>
|
||||
<IntegerSetting :path="[':pleroma','Pleroma.User.Backup',':process_chunk_size']" />
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting :path="[':pleroma','Pleroma.User.Backup',':timeout']" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.other.privileges') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<ListSetting path=":pleroma.:instance.:admin_privileges" />
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting path=":pleroma.:instance.:moderator_privileges" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./other_tab.js"></script>
|
||||
38
src/components/settings_modal/admin_tabs/posts_tab.js
Normal file
38
src/components/settings_modal/admin_tabs/posts_tab.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import ColorSetting from '../helpers/color_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue'
|
||||
import MapSetting from '../helpers/map_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const PostsTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
ColorSetting,
|
||||
AttachmentSetting,
|
||||
ListSetting,
|
||||
PWAManifestIconsSetting,
|
||||
MapSetting,
|
||||
GroupSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
export default PostsTab
|
||||
29
src/components/settings_modal/admin_tabs/posts_tab.vue
Normal file
29
src/components/settings_modal/admin_tabs/posts_tab.vue
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.posts')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.posts.global') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instances_favicons.:enabled" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.posts.local') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<ListSetting path=":pleroma.:instance.:allowed_post_formats" />
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.posts.remote') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<IntegerSetting path=":pleroma.:instance.:remote_post_retention_days" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:skip_thread_containment" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./posts_tab.js"></script>
|
||||
20
src/components/settings_modal/admin_tabs/rates_tab.js
Normal file
20
src/components/settings_modal/admin_tabs/rates_tab.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import RateSetting from '../helpers/rate_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const RatesTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
RateSetting,
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
export default RatesTab
|
||||
41
src/components/settings_modal/admin_tabs/rates_tab.vue
Normal file
41
src/components/settings_modal/admin_tabs/rates_tab.vue
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.instance')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.rate_limit.account_confirmation_resend') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:account_confirmation_resend" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:ap_routes" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:app_account_creation" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:authentication" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:oauth_app_creation" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:relation_id_action" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:search" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:status_id_action" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:statuses_actions" />
|
||||
</li>
|
||||
<li>
|
||||
<RateSetting path=":pleroma.:rate_limit.:timeline" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./rates_tab.js"></script>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
import TupleSetting from '../helpers/tuple_setting.vue'
|
||||
import GroupSetting from '../helpers/group_setting.vue'
|
||||
import AttachmentSetting from '../helpers/attachment_setting.vue'
|
||||
import ListSetting from '../helpers/list_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const RegistrationsTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting,
|
||||
TupleSetting,
|
||||
AttachmentSetting,
|
||||
GroupSetting,
|
||||
ListSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
export default RegistrationsTab
|
||||
182
src/components/settings_modal/admin_tabs/registrations_tab.vue
Normal file
182
src/components/settings_modal/admin_tabs/registrations_tab.vue
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.instance')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.instance.registrations') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:registrations_open" />
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path=":pleroma.:instance.:invites_enabled"
|
||||
parent-path=":pleroma.:instance.:registrations_open"
|
||||
parent-invert
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:birthday_required" />
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<IntegerSetting
|
||||
path=":pleroma.:instance.:birthday_min_age"
|
||||
parent-path=":pleroma.:instance.:birthday_required"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:account_activation_required" />
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path=":pleroma.:instance.:account_approval_required" />
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.instance.captcha_header') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting :path="[':pleroma', 'Pleroma.Captcha', ':enabled']" />
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<ChoiceSetting
|
||||
:path="[':pleroma', 'Pleroma.Captcha', ':method']"
|
||||
:parent-path="[':pleroma', 'Pleroma.Captcha', ':enabled']"
|
||||
:option-label-map="{
|
||||
'Pleroma.Captcha.Native': $t('admin_dash.captcha.native'),
|
||||
'Pleroma.Captcha.Kocaptcha': $t('admin_dash.captcha.kocaptcha')
|
||||
}"
|
||||
/>
|
||||
<IntegerSetting
|
||||
:path="[':pleroma', 'Pleroma.Captcha', ':seconds_valid']"
|
||||
:parent-path="[':pleroma', 'Pleroma.Captcha', ':enabled']"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
v-if="adminDraft[':pleroma']['Pleroma.Captcha'][':enabled'] && adminDraft[':pleroma']['Pleroma.Captcha'][':method'] === 'Pleroma.Captcha.Kocaptcha'"
|
||||
>
|
||||
<h5>{{ $t('admin_dash.instance.kocaptcha') }}</h5>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<StringSetting :path="[':pleroma', 'Pleroma.Captcha.Kocaptcha', ':endpoint']" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.registrations.autofollow') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<ListSetting
|
||||
path=":pleroma.:instance.:autofollowed_nicknames"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ListSetting
|
||||
path=":pleroma.:instance.:autofollowing_nicknames"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.registrations.welcome.title') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<p>{{ $t('admin_dash.registrations.welcome.description') }}</p>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.registrations.welcome.direct_message') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path=":pleroma.:welcome.:direct_message.:enabled"
|
||||
/>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<StringSetting
|
||||
path=":pleroma.:welcome.:direct_message.:sender_nickname"
|
||||
parent-path=":pleroma.:welcome.:direct_message.:enabled"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
path=":pleroma.:welcome.:direct_message.:message"
|
||||
parent-path=":pleroma.:welcome.:direct_message.:enabled"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:welcome.:direct_message" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.registrations.welcome.chat_message') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path=":pleroma.:welcome.:chat_message.:enabled"
|
||||
/>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<StringSetting
|
||||
tuple
|
||||
path=":pleroma.:welcome.:chat_message.:sender_nickname"
|
||||
parent-path=":pleroma.:welcome.:chat_message.:enabled"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
path=":pleroma.:welcome.:chat_message.:message"
|
||||
parent-path=":pleroma.:welcome.:chat_message.:enabled"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:welcome.:chat_message" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4>{{ $t('admin_dash.registrations.welcome.email_message') }}</h4>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path=":pleroma.:welcome.:email.:enabled"
|
||||
/>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<TupleSetting
|
||||
path=":pleroma.:welcome.:email.:sender"
|
||||
parent-path=":pleroma.:welcome.:email.:enabled"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
path=":pleroma.:welcome.:email.:subject"
|
||||
parent-path=":pleroma.:welcome.:email.:enabled"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
path=":pleroma.:welcome.:email.:html"
|
||||
parent-path=":pleroma.:welcome.:email.:enabled"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<GroupSetting path=":pleroma.:welcome.:email" />
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.registrations.restrictions') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<ListSetting
|
||||
ignore-suggestions
|
||||
:path="[':pleroma', 'Pleroma.User', ':email_blacklist']"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./registrations_tab.js"></script>
|
||||
46
src/components/settings_modal/admin_tabs/uploads_tab.js
Normal file
46
src/components/settings_modal/admin_tabs/uploads_tab.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||
import StringSetting from '../helpers/string_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
|
||||
const UploadsTab = {
|
||||
provide () {
|
||||
return {
|
||||
defaultDraftMode: true,
|
||||
defaultSource: 'admin'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
uploaders: [{
|
||||
key: 'Pleroma.Uploaders.Local',
|
||||
value: 'Pleroma.Uploaders.Local',
|
||||
label: this.$t('admin_dash.uploads.local_uploader')
|
||||
}, {
|
||||
key: 'Pleroma.Uploaders.IPFS',
|
||||
value: 'Pleroma.Uploaders.IPFS',
|
||||
label: 'IPFS'
|
||||
}, {
|
||||
key: 'Pleroma.Uploaders.S3',
|
||||
value: 'Pleroma.Uploaders.S3',
|
||||
label: 'S3'
|
||||
}]
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BooleanSetting,
|
||||
ChoiceSetting,
|
||||
IntegerSetting,
|
||||
StringSetting
|
||||
},
|
||||
computed: {
|
||||
uploader () {
|
||||
return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Upload'][':uploader']
|
||||
},
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
export default UploadsTab
|
||||
110
src/components/settings_modal/admin_tabs/uploads_tab.vue
Normal file
110
src/components/settings_modal/admin_tabs/uploads_tab.vue
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<template>
|
||||
<div :label="$t('admin_dash.tabs.uploads')">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('admin_dash.uploads.upload') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<ChoiceSetting
|
||||
:path="[':pleroma','Pleroma.Upload',':uploader']"
|
||||
:options="uploaders"
|
||||
/>
|
||||
<h4>{{ $t('admin_dash.uploads.uploader_settings') }}</h4>
|
||||
<ul class="setting-list suboptions">
|
||||
<template v-if="uploader === 'Pleroma.Uploaders.Local'">
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Uploaders.Local',':uploads']"
|
||||
/>
|
||||
</li>
|
||||
</template>
|
||||
<template v-else-if="uploader === 'Pleroma.Uploaders.IPFS'">
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Uploaders.IPFS',':get_gateway_url']"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Uploaders.IPFS',':post_gateway_url']"
|
||||
/>
|
||||
</li>
|
||||
</template>
|
||||
<template v-else-if="uploader === 'Pleroma.Uploaders.S3'">
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Uploaders.S3',':bucket']"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Uploaders.S3',':bucket_namespace']"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
:path="[':pleroma','Pleroma.Uploaders.S3',':streaming_enabled']"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Uploaders.S3',':truncated_namespace']"
|
||||
/>
|
||||
</li>
|
||||
</template>
|
||||
<li>
|
||||
<IntegerSetting
|
||||
:path="[':pleroma','Pleroma.Uploaders.Uploader',':timeout']"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ $t('admin_dash.uploads.attachments') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path=":pleroma.:instance.:attachment_links"
|
||||
:options="uploaders"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path=":pleroma.:instance.:cleanup_attachments"
|
||||
:options="uploaders"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- CONFIRM how filters work -->
|
||||
<h3>{{ $t('admin_dash.uploads.filenames') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<BooleanSetting
|
||||
:path="[':pleroma','Pleroma.Upload',':link_name']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<IntegerSetting
|
||||
:path="[':pleroma','Pleroma.Upload',':filename_display_max_length']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Upload',':default_description']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting
|
||||
:path="[':pleroma','Pleroma.Upload',':base_url']"
|
||||
:subgroup="adapter"
|
||||
/>
|
||||
</li>
|
||||
<!-- TODO: add mime-type when we have a dynamic list component -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./uploads_tab.js"></script>
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
<template>
|
||||
<span
|
||||
v-if="matchesExpertLevel"
|
||||
class="AttachmentSetting"
|
||||
class="AttachmentSetting setting-item"
|
||||
:class="{ '-compact': compact }"
|
||||
>
|
||||
<label
|
||||
class="setting-label"
|
||||
:for="path"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
<template>
|
||||
<label
|
||||
v-if="matchesExpertLevel"
|
||||
class="BooleanSetting"
|
||||
class="BooleanSetting setting-item"
|
||||
>
|
||||
<Checkbox
|
||||
class="setting-control setting-label"
|
||||
:model-value="visibleState"
|
||||
:disabled="shouldBeDisabled"
|
||||
:indeterminate="isIndeterminate"
|
||||
|
|
@ -13,6 +14,12 @@
|
|||
class="label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
{{ ' ' }}
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel }}
|
||||
</template>
|
||||
|
|
@ -22,19 +29,16 @@
|
|||
<slot v-else />
|
||||
</span>
|
||||
</Checkbox>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons />
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
v-if="backendDescriptionDescription || showDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
<slot name="description">
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</slot>
|
||||
</p>
|
||||
<DraftButtons />
|
||||
</label>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ export default {
|
|||
},
|
||||
props: {
|
||||
...Setting.props,
|
||||
overrideOptions: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
required: false
|
||||
|
|
@ -22,7 +26,16 @@ export default {
|
|||
computed: {
|
||||
...Setting.computed,
|
||||
realOptions () {
|
||||
if (this.overrideOptions) {
|
||||
return this.options
|
||||
}
|
||||
if (this.realSource === 'admin') {
|
||||
if (
|
||||
!this.backendDescriptionSuggestions?.length ||
|
||||
this.backendDescriptionSuggestions?.length === 0
|
||||
) {
|
||||
return this.options
|
||||
}
|
||||
return this.backendDescriptionSuggestions.map(x => ({
|
||||
key: x,
|
||||
value: x,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,27 @@
|
|||
<template>
|
||||
<label
|
||||
v-if="matchesExpertLevel"
|
||||
class="ChoiceSetting"
|
||||
class="ChoiceSetting setting-item"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot />
|
||||
</template>
|
||||
{{ ' ' }}
|
||||
<span class="setting-label">
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
{{ ' ' }}
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot />
|
||||
</template>
|
||||
</span>
|
||||
<Select
|
||||
:model-value="realDraftMode ? draft :state"
|
||||
:disabled="disabled"
|
||||
class="setting-control"
|
||||
:model-value="realDraftMode ? draft : state"
|
||||
:disabled="shouldBeDisabled"
|
||||
@update:model-value="update"
|
||||
>
|
||||
<option
|
||||
|
|
@ -24,11 +33,6 @@
|
|||
{{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }}
|
||||
</option>
|
||||
</Select>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons />
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
|
|
@ -40,3 +44,16 @@
|
|||
</template>
|
||||
|
||||
<script src="./choice_setting.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
.ChoiceSetting.setting-item {
|
||||
.-mobile & {
|
||||
display: block;
|
||||
|
||||
.setting-label {
|
||||
display: block;
|
||||
margin-bottom: 0.5em
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
16
src/components/settings_modal/helpers/color_setting.js
Normal file
16
src/components/settings_modal/helpers/color_setting.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import Setting from './setting.js'
|
||||
import ColorInput from 'src/components/color_input/color_input.vue'
|
||||
|
||||
export default {
|
||||
...Setting,
|
||||
components: {
|
||||
...Setting.components,
|
||||
ColorInput
|
||||
},
|
||||
methods: {
|
||||
...Setting.methods,
|
||||
getValue (e) {
|
||||
return e
|
||||
}
|
||||
}
|
||||
}
|
||||
71
src/components/settings_modal/helpers/color_setting.vue
Normal file
71
src/components/settings_modal/helpers/color_setting.vue
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<label
|
||||
v-if="matchesExpertLevel"
|
||||
class="ColorSetting setting-item"
|
||||
>
|
||||
<label
|
||||
v-if="!hideLabel"
|
||||
:for="path"
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
<template v-else-if="source === 'admin'">
|
||||
MISSING LABEL FOR {{ path }}
|
||||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
{{ ' ' }}
|
||||
<ColorInput
|
||||
:id="path"
|
||||
class="setting-control color-setting-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions"
|
||||
:model-value="realDraftMode ? draft : state"
|
||||
@update:model-value="update"
|
||||
/>
|
||||
{{ ' ' }}
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons v-if="!hideDraftButtons" />
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script src="./color_setting.js"></script>
|
||||
<style lang="scss">
|
||||
.ColorSetting {
|
||||
&.setting-item {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"label control"
|
||||
". desc"
|
||||
". draft";
|
||||
|
||||
.setting-label {
|
||||
text-align: right;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.setting-control {
|
||||
align-self: end;
|
||||
}
|
||||
}
|
||||
|
||||
.color-setting-input {
|
||||
align-self: baseline;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
<!-- TODO make it reusable -->
|
||||
<template>
|
||||
<span
|
||||
v-if="$parent.isDirty || $parent.canHardReset"
|
||||
class="DraftButtons"
|
||||
>
|
||||
<Popover
|
||||
|
|
@ -72,12 +73,10 @@ export default {
|
|||
|
||||
<style lang="scss">
|
||||
.DraftButtons {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
|
||||
.button-default {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
gap: 0.5em;
|
||||
margin-top: 0.5em
|
||||
}
|
||||
|
||||
.draft-tooltip {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,5 @@
|
|||
import { isEqual } from 'lodash'
|
||||
|
||||
import Setting from './setting.js'
|
||||
|
||||
export default {
|
||||
...Setting,
|
||||
computed: {
|
||||
...Setting.computed,
|
||||
isDirty () {
|
||||
return !isEqual(this.state, this.draft)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<span
|
||||
v-if="matchesExpertLevel"
|
||||
class="GroupSetting"
|
||||
class="GroupSetting setting-item"
|
||||
>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
|
|
|
|||
133
src/components/settings_modal/helpers/list_setting.js
Normal file
133
src/components/settings_modal/helpers/list_setting.js
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import Setting from './setting.js'
|
||||
|
||||
export default {
|
||||
...Setting,
|
||||
data () {
|
||||
return {
|
||||
newValue: '',
|
||||
}
|
||||
},
|
||||
components: {
|
||||
...Setting.components,
|
||||
Checkbox
|
||||
},
|
||||
props: {
|
||||
...Setting.props,
|
||||
ignoreSuggestions: {
|
||||
required: false,
|
||||
type: Boolean
|
||||
},
|
||||
overrideAvailableOptions: {
|
||||
required: false,
|
||||
type: Boolean
|
||||
},
|
||||
options: {
|
||||
required: false,
|
||||
type: Set
|
||||
},
|
||||
allowNew: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
forceNew: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...Setting.computed,
|
||||
showNew () {
|
||||
if (this.forceNew) return true
|
||||
if (!this.allowNew) return false
|
||||
|
||||
const isExpert = this.$store.state.config.expertLevel > 0
|
||||
const hasBuiltins = this.builtinEntries.length > 0
|
||||
|
||||
if (hasBuiltins) {
|
||||
return isExpert
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
valueSet () {
|
||||
return new Set(this.visibleState)
|
||||
},
|
||||
suggestionsSet () {
|
||||
const suggestions = this.backendDescriptionSuggestions
|
||||
if (suggestions) {
|
||||
return new Set(suggestions)
|
||||
} else {
|
||||
return new Set()
|
||||
}
|
||||
},
|
||||
extraEntries () {
|
||||
if (this.ignoreSuggestions) return [...this.valueSet.values()]
|
||||
if (!this.suggestionsSet) return []
|
||||
return [...this.valueSet.values()].filter((x) => {
|
||||
return !this.builtinEntriesValueSet.has(x)
|
||||
})
|
||||
},
|
||||
builtinEntries () {
|
||||
if (this.ignoreSuggestions) return []
|
||||
if (this.overrideAvailableOptions) {
|
||||
return [...this.options]
|
||||
}
|
||||
if (!this.suggestionsSet) return []
|
||||
|
||||
const builtins = [...this.suggestionsSet.values()]
|
||||
return builtins.map((option) => ({
|
||||
label: option,
|
||||
value: option
|
||||
}))
|
||||
},
|
||||
builtinEntriesValueSet () {
|
||||
return new Set(this.builtinEntries.map(x => x.value))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...Setting.methods,
|
||||
optionPresent (option) {
|
||||
return this.valueSet.has(option)
|
||||
},
|
||||
getValue ({ event, value, index, eventType }) {
|
||||
switch (eventType) {
|
||||
case 'toggle': {
|
||||
this.newValue = ''
|
||||
const newSet = new Set(this.valueSet.values())
|
||||
if (event) {
|
||||
newSet.add(value)
|
||||
} else {
|
||||
newSet.delete(value)
|
||||
}
|
||||
return [...newSet.values()]
|
||||
}
|
||||
|
||||
case 'add': {
|
||||
if (!this.newValue) return this.valueSet.values()
|
||||
const res = [...this.valueSet.values(), this.newValue]
|
||||
this.newValue = ''
|
||||
return res
|
||||
}
|
||||
|
||||
case 'remove': {
|
||||
const pre = [...this.valueSet.values()].slice(0, index)
|
||||
const post = [...this.valueSet.values()].slice(index + 1)
|
||||
|
||||
return [...pre, ...post]
|
||||
}
|
||||
|
||||
case 'edit': {
|
||||
const pre = [...this.valueSet.values()].slice(0, index)
|
||||
const post = [...this.valueSet.values()].slice(index + 1)
|
||||
const string = event.target.value
|
||||
if (!string) return [...this.valueSet.values()]
|
||||
|
||||
return [...pre, string, ...post]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
92
src/components/settings_modal/helpers/list_setting.vue
Normal file
92
src/components/settings_modal/helpers/list_setting.vue
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="matchesExpertLevel"
|
||||
class="ListSetting setting-item"
|
||||
>
|
||||
<label
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
<template v-else-if="source === 'admin'">
|
||||
MISSING LABEL FOR {{ path }}
|
||||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
<ul class="setting-list">
|
||||
<li
|
||||
v-for="(item, i) in builtinEntries"
|
||||
:key="i"
|
||||
>
|
||||
<Checkbox
|
||||
:disabled="shouldBeDisabled"
|
||||
:model-value="optionPresent(item.value)"
|
||||
@update:model-value="event => update({ event, value: item.value, eventType: 'toggle' })"
|
||||
>
|
||||
{{ item.label }}
|
||||
</Checkbox>
|
||||
</li>
|
||||
<li
|
||||
v-for="(item, index) in extraEntries"
|
||||
:key="index"
|
||||
>
|
||||
<div class="btn-group">
|
||||
<input
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:value="item"
|
||||
@change="e => update({ event: e, index, eventType: 'edit' })"
|
||||
>
|
||||
<button
|
||||
class="button-default"
|
||||
@click="e => update({ index, eventType: 'remove' })"
|
||||
>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="showNew">
|
||||
<div class="btn-group">
|
||||
<input
|
||||
v-model="newValue"
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
>
|
||||
<button
|
||||
class="button-default"
|
||||
@click="e => update({ eventType: 'add' })"
|
||||
>
|
||||
<FAIcon icon="plus" />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./list_setting.js"></script>
|
||||
<style lang="scss">
|
||||
.ListSetting {
|
||||
.setting-list {
|
||||
.checkbox {
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
44
src/components/settings_modal/helpers/list_tuple_setting.js
Normal file
44
src/components/settings_modal/helpers/list_tuple_setting.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import ListSetting from './list_setting.js'
|
||||
|
||||
export default {
|
||||
...ListSetting,
|
||||
data () {
|
||||
return {
|
||||
newValue: ['','']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...ListSetting.methods,
|
||||
getValue ({ event, index, eventType, tuple }) {
|
||||
switch (eventType) {
|
||||
case 'add': {
|
||||
if (!this.newValue[0] || !this.newValue[1]) return this.visibleState
|
||||
const res = [...this.visibleState, this.newValue]
|
||||
this.newValue = ['', '']
|
||||
return res
|
||||
}
|
||||
|
||||
case 'remove': {
|
||||
const pre = this.visibleState.slice(0, index)
|
||||
const post = this.visibleState.slice(index + 1)
|
||||
|
||||
return [...pre, ...post]
|
||||
}
|
||||
|
||||
case 'edit': {
|
||||
const pre = this.visibleState.slice(0, index)
|
||||
const post = this.visibleState.slice(index + 1)
|
||||
const item = this.visibleState[index]
|
||||
const string = event.target.value
|
||||
if (!string) return this.visibleState
|
||||
|
||||
if (tuple === 0) {
|
||||
return [...pre, [string, item[1]], ...post]
|
||||
} else {
|
||||
return [...pre, [item[0], string], ...post]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
src/components/settings_modal/helpers/list_tuple_setting.vue
Normal file
113
src/components/settings_modal/helpers/list_tuple_setting.vue
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="matchesExpertLevel"
|
||||
class="ListTupleSetting"
|
||||
>
|
||||
<label
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
<template v-else-if="source === 'admin'">
|
||||
MISSING LABEL FOR {{ path }}
|
||||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
<ul class="setting-list">
|
||||
<li
|
||||
v-for="(item, index) in visibleState"
|
||||
:key="index"
|
||||
>
|
||||
<div class="btn-group">
|
||||
<input
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:value="item.tuple[0]"
|
||||
@change="e => update({ event: e, index, eventType: 'edit', tuple: 0 })"
|
||||
>
|
||||
<input
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:value="item.tuple[1]"
|
||||
@change="e => update({ event: e, index, eventType: 'edit', tuple: 1 })"
|
||||
>
|
||||
<button
|
||||
class="button-default"
|
||||
@click="e => update({ index, eventType: 'remove' })"
|
||||
>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="btn-group">
|
||||
<input
|
||||
v-model="newValue[0]"
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions[0][0]"
|
||||
>
|
||||
<input
|
||||
v-model="newValue[1]"
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions[0][1]"
|
||||
>
|
||||
<button
|
||||
class="button-default"
|
||||
@click="e => update({ eventType: 'add' })"
|
||||
>
|
||||
<FAIcon icon="plus" />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./list_tuple_setting.js"></script>
|
||||
<style lang="scss">
|
||||
.ListTupleSetting {
|
||||
.btn-group {
|
||||
display: flex
|
||||
}
|
||||
|
||||
dl {
|
||||
display: inline-grid;
|
||||
grid-template-columns: auto auto;
|
||||
gap: 0.5em;
|
||||
align-items: baseline;
|
||||
|
||||
dt {
|
||||
display: inline;
|
||||
font-weight: 800;
|
||||
|
||||
&::after {
|
||||
content: ':'
|
||||
}
|
||||
}
|
||||
|
||||
dd {
|
||||
display: inline;
|
||||
margin: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
70
src/components/settings_modal/helpers/map_setting.js
Normal file
70
src/components/settings_modal/helpers/map_setting.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import Setting from './setting.js'
|
||||
|
||||
export default {
|
||||
...Setting,
|
||||
props: {
|
||||
...Setting.props,
|
||||
allowNew: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
newValue: ['',''] // avoiding extra complexity by just using an array instead of an object
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...Setting.computed,
|
||||
// state that we'll show in the UI, i.e. transforming map into list
|
||||
displayState () {
|
||||
return Object.entries(this.visibleState)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...Setting.methods,
|
||||
getValue ({ event, key, eventType, isKey }) {
|
||||
switch (eventType) {
|
||||
case 'add': {
|
||||
if (key === '') return this.visibleState
|
||||
const res = {...this.visibleState, ...Object.fromEntries([this.newValue])}
|
||||
this.newValue = ['', '']
|
||||
return res
|
||||
}
|
||||
|
||||
case 'remove': {
|
||||
// initial state for this type is empty array
|
||||
if (Array.isArray(this.visibleState)) return this.visibleState
|
||||
const newEntries = Object.entries(this.visibleState).filter(([k]) => k !== key)
|
||||
|
||||
if (newEntries.length === 0 ) return []
|
||||
return Object.fromEntries(newEntries)
|
||||
}
|
||||
|
||||
case 'edit': {
|
||||
const string = event.target.value
|
||||
const newEntries = Object
|
||||
.entries(this.visibleState)
|
||||
.map(([k, v]) => {
|
||||
if (isKey) {
|
||||
if (k === key) {
|
||||
return [string, v]
|
||||
} else {
|
||||
return [k, v]
|
||||
}
|
||||
} else {
|
||||
if (k === key) {
|
||||
return [k, string]
|
||||
} else {
|
||||
return [k, v]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return Object.fromEntries(newEntries)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
112
src/components/settings_modal/helpers/map_setting.vue
Normal file
112
src/components/settings_modal/helpers/map_setting.vue
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="matchesExpertLevel"
|
||||
class="MapSetting setting-item"
|
||||
>
|
||||
<label
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
<template v-else-if="source === 'admin'">
|
||||
MISSING LABEL FOR {{ path }}
|
||||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
<ul class="setting-list">
|
||||
<li
|
||||
v-for="(item, i) in displayState"
|
||||
:key="i"
|
||||
>
|
||||
<div class="btn-group">
|
||||
<input
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:value="item[0]"
|
||||
@change="e => update({ event: e, key: item[0], eventType: 'edit', isKey: true })"
|
||||
>
|
||||
<input
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:value="item[1]"
|
||||
@change="e => update({ event: e, key: item[0], eventType: 'edit', isKey: false })"
|
||||
>
|
||||
<button
|
||||
class="button-default"
|
||||
@click="e => update({ key: item[0], eventType: 'remove' })"
|
||||
>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="allowNew">
|
||||
<div class="btn-group">
|
||||
<input
|
||||
v-model="newValue[0]"
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions[0][0]"
|
||||
>
|
||||
<input
|
||||
v-model="newValue[1]"
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions[0][1]"
|
||||
>
|
||||
<button
|
||||
class="button-default"
|
||||
@click="e => update({ eventType: 'add' })"
|
||||
>
|
||||
<FAIcon icon="plus" />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./map_setting.js"></script>
|
||||
<style lang="scss">
|
||||
.MapSetting {
|
||||
.btn-group {
|
||||
display: flex
|
||||
}
|
||||
|
||||
dl {
|
||||
display: inline-grid;
|
||||
grid-template-columns: auto auto;
|
||||
gap: 0.5em;
|
||||
|
||||
dt {
|
||||
display: inline;
|
||||
font-weight: 800;
|
||||
|
||||
&::after {
|
||||
content: ':'
|
||||
}
|
||||
}
|
||||
|
||||
dd {
|
||||
display: inline;
|
||||
margin: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<span
|
||||
v-if="matchesExpertLevel"
|
||||
class="NumberSetting"
|
||||
class="NumberSetting setting-item"
|
||||
>
|
||||
<label
|
||||
v-if="!hideLabel"
|
||||
:for="path"
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<template v-if="backendDescriptionLabel">
|
||||
|
|
@ -18,10 +20,11 @@
|
|||
{{ ' ' }}
|
||||
<input
|
||||
:id="path"
|
||||
class="input number-input"
|
||||
class="input number-input setting-control"
|
||||
type="number"
|
||||
:step="step || 1"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions"
|
||||
:min="min || 0"
|
||||
:value="realDraftMode ? draft :state"
|
||||
@change="update"
|
||||
|
|
@ -32,7 +35,7 @@
|
|||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons />
|
||||
<DraftButtons v-if="!hideDraftButtons" />
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
|
|
|
|||
53
src/components/settings_modal/helpers/proxy_setting.js
Normal file
53
src/components/settings_modal/helpers/proxy_setting.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import Setting from './setting.js'
|
||||
|
||||
const getUrl = state => state?.tuple ? state.tuple[1] + ':' + state.tuple[2] : state
|
||||
const getSocks = state => state?.tuple
|
||||
|
||||
export default {
|
||||
...Setting,
|
||||
data () {
|
||||
return {
|
||||
urlField: '',
|
||||
socksField: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
Setting.created()
|
||||
this.urlField = getUrl(this.realDraftMode ? this.draft : this.state)
|
||||
this.socksField = getSocks(this.realDraftMode ? this.draft : this.state)
|
||||
},
|
||||
computed: {
|
||||
...Setting.computed,
|
||||
// state that we'll show in the UI, i.e. transforming map into list
|
||||
displayState () {
|
||||
if (this.visibleState?.tuple) {
|
||||
return this.visibleState.tuple[1] + ':' + this.visibleState.tuple[2]
|
||||
}
|
||||
return this.visibleState
|
||||
},
|
||||
socksState () {
|
||||
return getSocks(this.visibleState)
|
||||
}
|
||||
},
|
||||
components: {
|
||||
...Setting.components,
|
||||
Checkbox
|
||||
},
|
||||
methods: {
|
||||
...Setting.methods,
|
||||
getValue ({ event, isProxy}) {
|
||||
if (isProxy) {
|
||||
this.socksField = event
|
||||
} else {
|
||||
this.urlField = event.target.value
|
||||
}
|
||||
|
||||
if (this.socksField) {
|
||||
return { tuple: [ ':socks5', ...this.urlField.split(':') ] }
|
||||
} else {
|
||||
return this.urlField
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/components/settings_modal/helpers/proxy_setting.vue
Normal file
59
src/components/settings_modal/helpers/proxy_setting.vue
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<label
|
||||
v-if="matchesExpertLevel"
|
||||
class="ProxySetting setting-item"
|
||||
>
|
||||
<label
|
||||
v-if="!hideLabel"
|
||||
:for="path"
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
<template v-else-if="source === 'admin'">
|
||||
MISSING LABEL FOR {{ path }}
|
||||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
{{ ' ' }}
|
||||
<div class="setting-control">
|
||||
<input
|
||||
:id="path"
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions[0]"
|
||||
:value="displayState"
|
||||
@change="event => update({ event })"
|
||||
>
|
||||
{{ ' ' }}
|
||||
<Checkbox
|
||||
:model-value="socksState"
|
||||
:disabled="shouldBeDisabled"
|
||||
:indeterminate="isIndeterminate"
|
||||
@update:model-value="event => update({ event, isProxy: true})"
|
||||
>
|
||||
SOCKS5
|
||||
{{ ' ' }}
|
||||
</Checkbox>
|
||||
</div>
|
||||
{{ ' ' }}
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons v-if="!hideDraftButtons" />
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script src="./proxy_setting.js"></script>
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import { clone } from 'lodash'
|
||||
import { fileTypeExt } from 'src/services/file_type/file_type.service.js'
|
||||
|
||||
import Setting from './setting.js'
|
||||
import Select from 'src/components/select/select.vue'
|
||||
import Attachment from 'src/components/attachment/attachment.vue'
|
||||
import MediaUpload from 'src/components/media_upload/media_upload.vue'
|
||||
|
||||
export default {
|
||||
...Setting,
|
||||
components: {
|
||||
...Setting.components,
|
||||
Select,
|
||||
Attachment,
|
||||
MediaUpload
|
||||
},
|
||||
computed: {
|
||||
...Setting.computed,
|
||||
purposeOptions () {
|
||||
return ['any','monochrome','maskable'].map(value => ({
|
||||
value,
|
||||
key: value,
|
||||
label: this.$t('admin_dash.instance.pwa.icon.' + value)
|
||||
}))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...Setting.methods,
|
||||
attachment (e) {
|
||||
const path = e[':src']
|
||||
if (!path) {
|
||||
return {
|
||||
mimetype: '',
|
||||
url: ''
|
||||
}
|
||||
}
|
||||
const url = path.includes('://') ? path : this.$store.state.instance.server + path
|
||||
|
||||
return {
|
||||
mimetype: fileTypeExt(url),
|
||||
url
|
||||
}
|
||||
},
|
||||
setMediaFile ({ event, index }) {
|
||||
this.update({
|
||||
event: {
|
||||
target: {
|
||||
value: event.url
|
||||
},
|
||||
},
|
||||
index,
|
||||
eventType: 'edit',
|
||||
field: ':src'
|
||||
})
|
||||
},
|
||||
setPurpose ({ event, index }) {
|
||||
this.update({
|
||||
event: {
|
||||
target: {
|
||||
value: event
|
||||
},
|
||||
},
|
||||
index,
|
||||
eventType: 'edit',
|
||||
field: ':purpose'
|
||||
})
|
||||
},
|
||||
getValue ({ event, field, index, eventType }) {
|
||||
switch (eventType) {
|
||||
case 'add': {
|
||||
const res = [...this.visibleState, {}]
|
||||
return res
|
||||
}
|
||||
|
||||
case 'remove': {
|
||||
const pre = this.visibleState.slice(0, index)
|
||||
const post = this.visibleState.slice(index + 1)
|
||||
|
||||
return [...pre, ...post]
|
||||
}
|
||||
|
||||
case 'edit': {
|
||||
const pre = this.visibleState.slice(0, index)
|
||||
const post = this.visibleState.slice(index + 1)
|
||||
const item = clone(this.visibleState[index])
|
||||
const string = event.target.value
|
||||
|
||||
if (!string) {
|
||||
delete item[field]
|
||||
} else {
|
||||
item[field] = string
|
||||
}
|
||||
|
||||
return [...pre, item, ...post]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="matchesExpertLevel"
|
||||
class="PWAManifestIconsSetting setting-item"
|
||||
>
|
||||
<label
|
||||
class="pwa-label setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
{{ ' ' }}
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
<template v-else-if="source === 'admin'">
|
||||
MISSING LABEL FOR {{ path }}
|
||||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
<div class="setting-control">
|
||||
<ul class="item-list">
|
||||
<li
|
||||
v-if="visibleState.length === 0"
|
||||
class="no_items"
|
||||
>
|
||||
{{ $t('admin_dash.instance.pwa.no_icons') }}
|
||||
<button
|
||||
v-if="visibleState.length === 0"
|
||||
class="button-default add-button"
|
||||
@click="e => update({ eventType: 'add' })"
|
||||
>
|
||||
<FAIcon icon="plus" />
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
v-for="(item, index) in visibleState"
|
||||
:key="index"
|
||||
>
|
||||
<div class="icon-element">
|
||||
<div class="src-field">
|
||||
<Attachment
|
||||
class="src-attachment"
|
||||
:compact="compact"
|
||||
:attachment="attachment(item)"
|
||||
size="small"
|
||||
hide-description
|
||||
/>
|
||||
<div class="src-url">
|
||||
<label for="path">{{ $t('settings.url') }}</label>
|
||||
<input
|
||||
:id="path"
|
||||
class="input string-input"
|
||||
:disabled="shouldBeDisabled"
|
||||
:value="item[':src']"
|
||||
@change="event => update({ event, index, eventType: 'edit', field: ':src' })"
|
||||
>
|
||||
</div>
|
||||
<MediaUpload
|
||||
ref="mediaUpload"
|
||||
class="src-upload media-upload-icon"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
normal-button
|
||||
:accept-types="acceptTypes"
|
||||
@uploaded="event => setMediaFile({ event, index })"
|
||||
/>
|
||||
</div>
|
||||
<dl>
|
||||
<dt>{{ $t('admin_dash.instance.pwa.icon.purpose') }}</dt>
|
||||
<dd>
|
||||
<Select
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:model-value="item[':purpose']"
|
||||
@update:model-value="event => setPurpose({ event, index })"
|
||||
>
|
||||
<option
|
||||
v-for="(purpose, index) in purposeOptions"
|
||||
:key="index"
|
||||
:value="purpose.value"
|
||||
>
|
||||
{{ purpose.label }}
|
||||
</option>
|
||||
</Select>
|
||||
</dd>
|
||||
<dt><code>sizes</code>{{ $t('admin_dash.instance.pwa.optional') }}</dt>
|
||||
<dd>
|
||||
<input
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:value="item[':sizes']"
|
||||
@change="e => update({ event: e, index, eventType: 'edit', field: ':sizes' })"
|
||||
>
|
||||
</dd>
|
||||
<dt><code>type</code>{{ $t('admin_dash.instance.pwa.optional') }}</dt>
|
||||
<dd>
|
||||
<input
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:value="item[':type']"
|
||||
@change="e => update({ event: e, index, eventType: 'edit', field: ':type' })"
|
||||
>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="buttons">
|
||||
<button
|
||||
v-if="index === visibleState.length - 1"
|
||||
class="button-default add-button"
|
||||
@click="e => update({ eventType: 'add' })"
|
||||
>
|
||||
<FAIcon icon="plus" />
|
||||
</button>
|
||||
<button
|
||||
class="button-default delete-button"
|
||||
@click="e => update({ index, eventType: 'remove' })"
|
||||
>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./pwa_manifest_icons_setting.js"></script>
|
||||
<style lang="scss">
|
||||
div.PWAManifestIconsSetting {
|
||||
margin-left: 3em;
|
||||
|
||||
&.setting-item {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"label"
|
||||
"desc"
|
||||
"control"
|
||||
"draft";
|
||||
grid-template-rows: 2em auto 1fr;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.pwa-label.setting-label {
|
||||
align-self: end;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
justify-content: right;
|
||||
margin-top: 0.5em;
|
||||
|
||||
button {
|
||||
line-height: 2;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, 12em);
|
||||
grid-gap: 2em;
|
||||
}
|
||||
|
||||
dl {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
margin-top: 0.5em;
|
||||
gap: 0.25em;
|
||||
align-items: baseline;
|
||||
|
||||
dt {
|
||||
font-weight: 800;
|
||||
|
||||
&::after {
|
||||
content: ':'
|
||||
}
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 0
|
||||
}
|
||||
}
|
||||
|
||||
.src-field {
|
||||
display: grid;
|
||||
grid-template-columns: auto;
|
||||
justify-items: center;
|
||||
gap: 0.5em;
|
||||
|
||||
.src-attachment {
|
||||
width: 10em;
|
||||
height: 10em;
|
||||
display: block;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.src-upload {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.src-url {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25em;
|
||||
width: 100%;
|
||||
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
53
src/components/settings_modal/helpers/rate_setting.js
Normal file
53
src/components/settings_modal/helpers/rate_setting.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import Setting from './setting.js'
|
||||
|
||||
export default {
|
||||
...Setting,
|
||||
data () {
|
||||
return {
|
||||
newValue: '',
|
||||
}
|
||||
},
|
||||
components: {
|
||||
...Setting.components,
|
||||
Checkbox
|
||||
},
|
||||
props: {
|
||||
...Setting.props
|
||||
},
|
||||
computed: {
|
||||
...Setting.computed,
|
||||
isSeparate () {
|
||||
// [[a1, b1], [a2, b2]] vs [a, b]
|
||||
return Array.isArray(this.visibleState[0])
|
||||
},
|
||||
normalizedState () {
|
||||
if (this.isSeparate) {
|
||||
return this.visibleState.map(y => y.map(x => Number(x) || 0))
|
||||
} else {
|
||||
return [this.visibleState.map(x => Number(x) || 0)]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...Setting.methods,
|
||||
getValue ({ event, side, index, eventType }) {
|
||||
if (eventType === 'edit') {
|
||||
const value = Number(event.target.value)
|
||||
if (Number.isNaN(value)) return this.visibleState
|
||||
|
||||
const newVal = [...this.normalizedState.map(x => [...x])]
|
||||
newVal[side][index] = value
|
||||
return newVal
|
||||
}
|
||||
|
||||
if (eventType === 'toggleMode') {
|
||||
if (event === 'split') {
|
||||
return [this.normalizedState[0], this.normalizedState[0]]
|
||||
} else if (event === 'join') {
|
||||
return [this.normalizedState[0]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
139
src/components/settings_modal/helpers/rate_setting.vue
Normal file
139
src/components/settings_modal/helpers/rate_setting.vue
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="matchesExpertLevel"
|
||||
class="RateSetting setting-item"
|
||||
>
|
||||
<label
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
{{ ' ' }}
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
<template v-else-if="source === 'admin'">
|
||||
MISSING LABEL FOR {{ path }}
|
||||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
<div class="setting-control">
|
||||
<table>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>
|
||||
{{ $t('admin_dash.rate_limit.period') }}
|
||||
</th>
|
||||
<th>
|
||||
{{ $t('admin_dash.rate_limit.amount') }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td v-if="isSeparate">
|
||||
{{ $t('admin_dash.rate_limit.unauthenticated') }}
|
||||
</td>
|
||||
<td v-else>
|
||||
{{ $t('admin_dash.rate_limit.rate_limit') }}
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[0][0]"
|
||||
@change="e => update({ event: e, index: 0, side: 0, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[0][1]"
|
||||
@change="e => update({ event: e, index: 1, side: 0, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="isSeparate">
|
||||
<td>
|
||||
{{ $t('admin_dash.rate_limit.authenticated') }}
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[1][0]"
|
||||
@change="e => update({ event: e, index: 0, side: 1, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[1][1]"
|
||||
@change="e => update({ event: e, index: 1, side: 1, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<Checkbox
|
||||
:model-value="isSeparate"
|
||||
@update:model-value="event => update({ event: event ? 'join' : 'split', eventType: 'toggleMode' })"
|
||||
>
|
||||
{{ $t('admin_dash.rate_limit.separate') }}
|
||||
</Checkbox>
|
||||
</div>
|
||||
<DraftButtons />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./rate_setting.js"></script>
|
||||
<style lang="scss">
|
||||
.RateSetting {
|
||||
&.setting-item {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"label control"
|
||||
"desc control"
|
||||
". draft";
|
||||
|
||||
.setting-label {
|
||||
text-align: right;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.setting-description {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.setting-control {
|
||||
align-self: end;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
td {
|
||||
input {
|
||||
width: 15ch;
|
||||
}
|
||||
}
|
||||
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import ModifiedIndicator from './modified_indicator.vue'
|
||||
import ProfileSettingIndicator from './profile_setting_indicator.vue'
|
||||
import DraftButtons from './draft_buttons.vue'
|
||||
import { get, set, cloneDeep } from 'lodash'
|
||||
import { get, set, cloneDeep, isEqual } from 'lodash'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -18,6 +18,22 @@ export default {
|
|||
type: [String, Array],
|
||||
required: false
|
||||
},
|
||||
showDescription: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
},
|
||||
descriptionPathOverride: {
|
||||
type: [String, Array],
|
||||
required: false
|
||||
},
|
||||
suggestions: {
|
||||
type: [String, Array],
|
||||
required: false
|
||||
},
|
||||
subgroup: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
|
|
@ -37,17 +53,27 @@ export default {
|
|||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
hideDraftButtons: { // this is for the weird backend hybrid (Boolean|String or Boolean|Number) settings
|
||||
required: false,
|
||||
type: Boolean
|
||||
},
|
||||
hideLabel: {
|
||||
type: Boolean
|
||||
},
|
||||
hideDescription: {
|
||||
type: Boolean
|
||||
},
|
||||
swapDescriptionAndLabel: {
|
||||
type: Boolean
|
||||
},
|
||||
backendDescriptionPath: {
|
||||
type: [String, Array]
|
||||
},
|
||||
overrideBackendDescription: {
|
||||
type: Boolean
|
||||
},
|
||||
overrideBackendDescriptionLabel: {
|
||||
type: Boolean
|
||||
type: [Boolean, String]
|
||||
},
|
||||
draftMode: {
|
||||
type: Boolean,
|
||||
|
|
@ -73,7 +99,7 @@ export default {
|
|||
},
|
||||
created () {
|
||||
if (this.realDraftMode && (this.realSource !== 'admin' || this.path == null)) {
|
||||
this.draft = this.state
|
||||
this.draft = cloneDeep(this.state)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -114,10 +140,13 @@ export default {
|
|||
return typeof this.draftMode === 'undefined' ? this.defaultDraftMode : this.draftMode
|
||||
},
|
||||
backendDescription () {
|
||||
return get(this.$store.state.adminSettings.descriptions, this.path)
|
||||
return get(this.$store.state.adminSettings.descriptions, this.descriptionPath)
|
||||
},
|
||||
backendDescriptionLabel () {
|
||||
if (this.realSource !== 'admin') return ''
|
||||
if (this.overrideBackendDescriptionLabel !== '' && typeof this.overrideBackendDescriptionLabel === 'string') {
|
||||
return this.overrideBackendDescriptionLabel
|
||||
}
|
||||
if (!this.backendDescription || this.overrideBackendDescriptionLabel) {
|
||||
return this.$t([
|
||||
'admin_dash',
|
||||
|
|
@ -132,6 +161,7 @@ export default {
|
|||
}
|
||||
},
|
||||
backendDescriptionDescription () {
|
||||
if (this.description) return this.description
|
||||
if (this.realSource !== 'admin') return ''
|
||||
if (this.hideDescription) return null
|
||||
if (!this.backendDescription || this.overrideBackendDescription) {
|
||||
|
|
@ -148,13 +178,20 @@ export default {
|
|||
}
|
||||
},
|
||||
backendDescriptionSuggestions () {
|
||||
return this.backendDescription?.suggestions
|
||||
return this.backendDescription?.suggestions || this.suggestions
|
||||
},
|
||||
shouldBeDisabled () {
|
||||
if (this.path == null) {
|
||||
return this.disabled
|
||||
}
|
||||
const parentValue = this.parentPath !== undefined ? get(this.configSource, this.parentPath) : null
|
||||
let parentValue = null
|
||||
if (this.parentPath !== undefined && this.realSource === 'admin') {
|
||||
if (this.realDraftMode) {
|
||||
parentValue = get(this.$store.state.adminSettings.draft, this.parentPath)
|
||||
} else {
|
||||
parentValue = get(this.configSource, this.parentPath)
|
||||
}
|
||||
}
|
||||
return this.disabled || (parentValue !== null ? (this.parentInvert ? parentValue : !parentValue) : false)
|
||||
},
|
||||
configSource () {
|
||||
|
|
@ -209,17 +246,29 @@ export default {
|
|||
if (this.path == null) return null
|
||||
return Array.isArray(this.path) ? this.path : this.path.split('.')
|
||||
},
|
||||
descriptionPath () {
|
||||
if (this.path == null) return null
|
||||
if (this.descriptionPathOverride) return this.descriptionPathOverride
|
||||
const path = Array.isArray(this.path) ? this.path : this.path.split('.')
|
||||
if (this.subgroup) {
|
||||
return [
|
||||
...path.slice(0, path.length - 1),
|
||||
':subgroup,' + this.subgroup,
|
||||
...path.slice(path.length - 1)
|
||||
]
|
||||
}
|
||||
return path
|
||||
},
|
||||
isDirty () {
|
||||
if (this.path == null) return false
|
||||
if (this.realSource === 'admin' && this.canonPath.length > 3) {
|
||||
return false // should not show draft buttons for "grouped" values
|
||||
} else {
|
||||
return this.realDraftMode && this.draft !== this.state
|
||||
return this.realDraftMode && !isEqual(this.draft, this.state)
|
||||
}
|
||||
},
|
||||
canHardReset () {
|
||||
return this.realSource === 'admin' && this.$store.state.adminSettings.modifiedPaths &&
|
||||
this.$store.state.adminSettings.modifiedPaths.has(this.canonPath.join(' -> '))
|
||||
return this.realSource === 'admin' && this.$store.state.adminSettings.modifiedPaths?.has(this.canonPath.join(' -> '))
|
||||
},
|
||||
matchesExpertLevel () {
|
||||
return (this.expert || 0) <= this.$store.state.config.expertLevel > 0
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
<template>
|
||||
<label
|
||||
<span
|
||||
v-if="matchesExpertLevel"
|
||||
class="StringSetting"
|
||||
class="StringSetting setting-item"
|
||||
>
|
||||
<label
|
||||
v-if="!hideLabel"
|
||||
:for="path"
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
{{ ' ' }}
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
|
|
@ -16,21 +23,17 @@
|
|||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
{{ ' ' }}
|
||||
<input
|
||||
:id="path"
|
||||
class="input string-input"
|
||||
class="setting-control input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions"
|
||||
:value="realDraftMode ? draft : state"
|
||||
@change="update"
|
||||
>
|
||||
{{ ' ' }}
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
<DraftButtons />
|
||||
<DraftButtons v-if="!hideDraftButtons" />
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
|
|
@ -38,7 +41,7 @@
|
|||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
</label>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script src="./string_setting.js"></script>
|
||||
|
|
|
|||
16
src/components/settings_modal/helpers/tuple_setting.js
Normal file
16
src/components/settings_modal/helpers/tuple_setting.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import Setting from './setting.js'
|
||||
|
||||
export default {
|
||||
...Setting,
|
||||
methods: {
|
||||
...Setting.methods,
|
||||
getValue ({ e, side }) {
|
||||
const [a, b] = this.visibleState || []
|
||||
if (side === 0) {
|
||||
return { tuple: [e.target.value, b]}
|
||||
} else {
|
||||
return { tuple: [a, e.target.value]}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/components/settings_modal/helpers/tuple_setting.vue
Normal file
58
src/components/settings_modal/helpers/tuple_setting.vue
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<span
|
||||
v-if="matchesExpertLevel"
|
||||
class="setting-item"
|
||||
>
|
||||
<label
|
||||
v-if="!hideLabel"
|
||||
:for="path"
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="isProfileSetting" />
|
||||
{{ ' ' }}
|
||||
<template v-if="backendDescriptionLabel">
|
||||
{{ backendDescriptionLabel + ' ' }}
|
||||
</template>
|
||||
<template v-else-if="source === 'admin'">
|
||||
MISSING LABEL FOR {{ path }}
|
||||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
<span class="setting-control">
|
||||
<input
|
||||
:id="path"
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions?.[0]?.[0]"
|
||||
:value="visibleState?.tuple?.[0]"
|
||||
@change="e => update({ e, side: 0 })"
|
||||
>
|
||||
{{ ' ' }}
|
||||
<input
|
||||
:id="path"
|
||||
class="input string-input"
|
||||
:class="{ disabled: shouldBeDisabled }"
|
||||
:disabled="shouldBeDisabled"
|
||||
:placeholder="backendDescriptionSuggestions?.[0]?.[1]"
|
||||
:value="visibleState?.tuple?.[1]"
|
||||
@change="e => update({ e, side: 1 })"
|
||||
>
|
||||
</span>
|
||||
<DraftButtons v-if="!hideDraftButtons" />
|
||||
<p
|
||||
v-if="backendDescriptionDescription"
|
||||
class="setting-description"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
{{ backendDescriptionDescription + ' ' }}
|
||||
</p>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script src="./tuple_setting.js"></script>
|
||||
|
|
@ -1,16 +1,20 @@
|
|||
<template>
|
||||
<span
|
||||
v-if="matchesExpertLevel"
|
||||
class="UnitSetting"
|
||||
class="UnitSetting setting-item"
|
||||
>
|
||||
<label
|
||||
:for="path"
|
||||
class="size-label"
|
||||
class="setting-label size-label"
|
||||
>
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
{{ ' ' }}
|
||||
<slot />
|
||||
</label>
|
||||
{{ ' ' }}
|
||||
<span class="no-break">
|
||||
<span class="no-break setting-control">
|
||||
<input
|
||||
:id="path"
|
||||
class="input number-input"
|
||||
|
|
@ -38,10 +42,6 @@
|
|||
</Select>
|
||||
</span>
|
||||
{{ ' ' }}
|
||||
<ModifiedIndicator
|
||||
:changed="isChanged"
|
||||
:onclick="reset"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<style lang="scss">
|
||||
.UnitSetting {
|
||||
.no-break {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.number-input {
|
||||
|
|
|
|||
|
|
@ -159,11 +159,13 @@ export default {
|
|||
|
||||
const wrapperClasses = ['tab-content-wrapper', active ? '-active' : '-hidden' ]
|
||||
const contentClasses = ['tab-content']
|
||||
if (props['full-width']) {
|
||||
if (props['full-width'] || props['full-width'] === '') {
|
||||
contentClasses.push('-full-width')
|
||||
wrapperClasses.push('-full-width')
|
||||
}
|
||||
if (props['full-height']) {
|
||||
if (props['full-height'] || props['full-width'] === '') {
|
||||
contentClasses.push('-full-height')
|
||||
wrapperClasses.push('-full-height')
|
||||
}
|
||||
return (
|
||||
<div class={wrapperClasses} >
|
||||
|
|
|
|||
|
|
@ -26,24 +26,6 @@
|
|||
}
|
||||
|
||||
> .contents {
|
||||
flex: 1 0 35em;
|
||||
|
||||
.tab-content {
|
||||
align-self: center;
|
||||
|
||||
&:not(.-full-width) {
|
||||
max-width: 40em;
|
||||
}
|
||||
|
||||
&.-full-width {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
&.-full-height {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content-label {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
|
|
@ -60,8 +42,24 @@
|
|||
flex: 1 1 auto;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(1em, 1fr) minmax(min-content, 45em) minmax(1em, 1fr);
|
||||
grid-template-areas: ". content .";
|
||||
flex-direction: column;
|
||||
|
||||
.tab-content {
|
||||
grid-area: content;
|
||||
|
||||
&.-full-width {
|
||||
grid-column: 1 / 4;
|
||||
}
|
||||
|
||||
&.-full-height {
|
||||
> * {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content-wrapper {
|
||||
|
|
@ -109,6 +107,10 @@
|
|||
flex-shrink: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-slot-wrapper {
|
||||
grid-template-columns: 0 minmax(min-content, 45em) 0;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (container-type: inline-size) {
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ const SettingsModal = {
|
|||
},
|
||||
computed: {
|
||||
...mapState(useInterfaceStore, {
|
||||
temporaryChangesTimeoutId: store => store.temporaryChangesTimeoutId,
|
||||
temporaryChangesCountdown: store => store.temporaryChangesCountdown,
|
||||
currentSaveStateNotice: store => store.settings.currentSaveStateNotice,
|
||||
modalActivated: store => store.settingsModalState !== 'hidden',
|
||||
modalMode: store => store.settingsModalMode,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
font-weight: 500;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
|
|
@ -13,6 +14,7 @@
|
|||
font-weight: 500;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
margin-right: 1em;
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding-bottom: 0.25em;
|
||||
box-sizing: border-box;
|
||||
|
|
@ -22,36 +24,133 @@
|
|||
h4 {
|
||||
font-size: 1.1rem;
|
||||
margin-top: 1em;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.5em;
|
||||
margin-top: 0;
|
||||
margin-left: 1em;
|
||||
margin-bottom: 0.25em;
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.suboptions {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.sidenote {
|
||||
margin-left: 5em;
|
||||
padding: 0.25em 1em;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.setting-description {
|
||||
margin-top: 0.2em;
|
||||
margin-bottom: 0;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.setting-item {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"label control"
|
||||
"label desc"
|
||||
". draft";
|
||||
grid-template-columns: 4fr 5fr;
|
||||
column-gap: 0.5em;
|
||||
align-items: baseline;
|
||||
padding: 0.5em 0;
|
||||
|
||||
.setting-label {
|
||||
grid-area: label;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ModifiedIndicator,
|
||||
.ProfileSettingIndicator {
|
||||
grid-area: indicator;
|
||||
}
|
||||
|
||||
.setting-control {
|
||||
grid-area: control;
|
||||
|
||||
&.textarea {
|
||||
align-self: baseline;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&.checkbox {
|
||||
display: grid;
|
||||
grid-template-columns: subgrid;
|
||||
|
||||
.label {
|
||||
grid-area: label;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.checkbox-indicator {
|
||||
grid-area: control;
|
||||
}
|
||||
|
||||
.-mobile & {
|
||||
.label {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.setting-control.setting-label {
|
||||
grid-column: 1 / 3;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.setting-description {
|
||||
grid-area: desc;
|
||||
}
|
||||
|
||||
.DraftButtons {
|
||||
grid-area: draft;
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-tab-switcher {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.setting-list,
|
||||
.option-list {
|
||||
list-style-type: none;
|
||||
padding-left: 2em;
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
|
||||
.btn:not(.dropdown-button) {
|
||||
padding: 0 2em;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.suboptions {
|
||||
margin-top: 0.3em;
|
||||
.btn-group {
|
||||
.button-default {
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.two-column {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
margin-left: 2em;
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding-bottom: 0.5em;
|
||||
margin-bottom: 1em;
|
||||
|
||||
.setting-item {
|
||||
grid-template-columns: 3fr 1fr;
|
||||
}
|
||||
|
||||
> li {
|
||||
margin: 0;
|
||||
|
|
@ -60,12 +159,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.setting-description {
|
||||
margin-top: 0.2em;
|
||||
margin-bottom: 2em;
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
.settings-modal-panel {
|
||||
overflow: hidden;
|
||||
transition: transform;
|
||||
|
|
@ -114,20 +207,39 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
.setting-item {
|
||||
grid-template-columns: 1fr min-content;
|
||||
column-gap: 0.5em;
|
||||
padding: 1em;
|
||||
align-items: center;
|
||||
|
||||
.setting-label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
.label {
|
||||
text-align: left;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
|
||||
li:not(:first-child) {
|
||||
.setting-item {
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.setting-list:not(.suboptions),
|
||||
.option-list {
|
||||
padding-left: 0.25em;
|
||||
|
||||
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
// it makes no sense
|
||||
> li {
|
||||
margin: 1em 0;
|
||||
line-height: 1.5em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* stylelint-enable no-descending-specificity */
|
||||
|
||||
&.two-column {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,14 +158,14 @@
|
|||
</div>
|
||||
<teleport to="#modal">
|
||||
<ConfirmModal
|
||||
v-if="temporaryChangesTimeoutId"
|
||||
v-if="temporaryChangesCountdown > 0"
|
||||
:title="$t('settings.confirm_new_setting')"
|
||||
:cancel-text="$t('settings.revert')"
|
||||
:confirm-text="$t('settings.confirm')"
|
||||
@cancelled="temporaryChangesRevert"
|
||||
@accepted="temporaryChangesConfirm"
|
||||
>
|
||||
{{ $t('settings.confirm_new_question') }}
|
||||
{{ $t('settings.confirm_new_question_countdown', temporaryChangesCountdown) }}
|
||||
</ConfirmModal>
|
||||
</teleport>
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -1,32 +1,61 @@
|
|||
import VerticalTabSwitcher from './helpers/vertical_tab_switcher.jsx'
|
||||
|
||||
import InstanceTab from './admin_tabs/instance_tab.vue'
|
||||
import LinksTab from './admin_tabs/links_tab.vue'
|
||||
import LimitsTab from './admin_tabs/limits_tab.vue'
|
||||
import FrontendsTab from './admin_tabs/frontends_tab.vue'
|
||||
import MediaProxyTab from './admin_tabs/media_proxy_tab.vue'
|
||||
import EmojiTab from './admin_tabs/emoji_tab.vue'
|
||||
import UploadsTab from './admin_tabs/uploads_tab.vue'
|
||||
import MailerTab from './admin_tabs/mailer_tab.vue'
|
||||
import MonitoringTab from './admin_tabs/monitoring_tab.vue'
|
||||
import RegistrationsTab from './admin_tabs/registrations_tab.vue'
|
||||
import AuthTab from './admin_tabs/auth_tab.vue'
|
||||
import HTTPTab from './admin_tabs/http_tab.vue'
|
||||
import OtherTab from './admin_tabs/other_tab.vue'
|
||||
import RatesTab from './admin_tabs/rates_tab.vue'
|
||||
import PostsTab from './admin_tabs/posts_tab.vue'
|
||||
import FederationTab from './admin_tabs/federation_tab.vue'
|
||||
import JobQueuesTab from './admin_tabs/job_queues_tab.vue'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faWrench,
|
||||
faHand,
|
||||
faChain,
|
||||
faGlobe,
|
||||
faLaptopCode,
|
||||
faPaintBrush,
|
||||
faBell,
|
||||
faDownload,
|
||||
faEyeSlash,
|
||||
faInfo
|
||||
faTowerBroadcast,
|
||||
faEnvelope,
|
||||
faChartLine,
|
||||
faDoorOpen,
|
||||
faGears,
|
||||
faKey,
|
||||
faCircleNodes,
|
||||
faUpload,
|
||||
faMessage,
|
||||
faEllipsis,
|
||||
faGauge
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faWrench,
|
||||
faHand,
|
||||
faChain,
|
||||
faGlobe,
|
||||
faLaptopCode,
|
||||
faPaintBrush,
|
||||
faBell,
|
||||
faDownload,
|
||||
faEyeSlash,
|
||||
faInfo
|
||||
faTowerBroadcast,
|
||||
faEnvelope,
|
||||
faChartLine,
|
||||
faDoorOpen,
|
||||
faGears,
|
||||
faKey,
|
||||
faCircleNodes,
|
||||
faUpload,
|
||||
faMessage,
|
||||
faEllipsis,
|
||||
faGauge
|
||||
)
|
||||
|
||||
const SettingsModalAdminContent = {
|
||||
|
|
@ -34,9 +63,22 @@ const SettingsModalAdminContent = {
|
|||
VerticalTabSwitcher,
|
||||
|
||||
InstanceTab,
|
||||
LimitsTab,
|
||||
RegistrationsTab,
|
||||
EmojiTab,
|
||||
FrontendsTab,
|
||||
EmojiTab
|
||||
FederationTab,
|
||||
LimitsTab,
|
||||
MailerTab,
|
||||
UploadsTab,
|
||||
MediaProxyTab,
|
||||
LinksTab,
|
||||
JobQueuesTab,
|
||||
AuthTab,
|
||||
HTTPTab,
|
||||
MonitoringTab,
|
||||
RatesTab,
|
||||
OtherTab,
|
||||
PostsTab
|
||||
},
|
||||
computed: {
|
||||
user () {
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
.settings_tab-switcher {
|
||||
height: 100%;
|
||||
|
||||
.setting-item {
|
||||
border-bottom: 2px solid var(--border);
|
||||
margin: 1em 1em 1.4em;
|
||||
padding-bottom: 1.4em;
|
||||
|
||||
> div,
|
||||
> label {
|
||||
display: block;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-multiple {
|
||||
margin-top: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.option-list {
|
||||
margin: 0;
|
||||
margin-top: 0.5em;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.unavailable,
|
||||
.unavailable svg {
|
||||
color: var(--cRed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
<vertical-tab-switcher
|
||||
v-if="adminDescriptionsLoaded && (noDb || adminDbLoaded)"
|
||||
ref="tabSwitcher"
|
||||
class="settings_tab-switcher"
|
||||
class="settings-admin-content settings_tab-switcher"
|
||||
:side-tab-bar="true"
|
||||
:scrollable-tabs="true"
|
||||
:render-only-focused="true"
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
data-tab-name="nodb-notice"
|
||||
>
|
||||
<div :label="$t('admin_dash.tabs.nodb')">
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h2>{{ $t('admin_dash.nodb.heading') }}</h2>
|
||||
<i18n-t
|
||||
scope="global"
|
||||
|
|
@ -48,6 +48,41 @@
|
|||
>
|
||||
<InstanceTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.registrations')"
|
||||
icon="door-open"
|
||||
data-tab-name="registrations"
|
||||
>
|
||||
<RegistrationsTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.auth')"
|
||||
icon="key"
|
||||
data-tab-name="monitoring"
|
||||
>
|
||||
<AuthTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.emoji')"
|
||||
icon="face-smile-beam"
|
||||
data-tab-name="emoji"
|
||||
full-width
|
||||
>
|
||||
<EmojiTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.frontends')"
|
||||
icon="laptop-code"
|
||||
data-tab-name="frontends"
|
||||
full-width
|
||||
>
|
||||
<FrontendsTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="adminDbLoaded"
|
||||
:label="$t('admin_dash.tabs.limits')"
|
||||
|
|
@ -56,24 +91,104 @@
|
|||
>
|
||||
<LimitsTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.frontends')"
|
||||
icon="laptop-code"
|
||||
data-tab-name="frontends"
|
||||
v-if="adminDbLoaded"
|
||||
:label="$t('admin_dash.tabs.rate_limit')"
|
||||
icon="gauge"
|
||||
data-tab-name="rate_limits"
|
||||
>
|
||||
<FrontendsTab />
|
||||
<RatesTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.emoji')"
|
||||
icon="face-smile-beam"
|
||||
data-tab-name="emoji"
|
||||
:label="$t('admin_dash.tabs.uploads')"
|
||||
icon="upload"
|
||||
data-tab-name="uploads"
|
||||
>
|
||||
<EmojiTab />
|
||||
<UploadsTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.media_proxy')"
|
||||
icon="tower-broadcast"
|
||||
data-tab-name="media_proxy"
|
||||
>
|
||||
<MediaProxyTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.posts')"
|
||||
icon="message"
|
||||
data-tab-name="other"
|
||||
>
|
||||
<PostsTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.links')"
|
||||
icon="chain"
|
||||
data-tab-name="links"
|
||||
>
|
||||
<LinksTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.mailer')"
|
||||
icon="envelope"
|
||||
data-tab-name="mailer"
|
||||
>
|
||||
<MailerTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.federation')"
|
||||
icon="circle-nodes"
|
||||
data-tab-name="monitoring"
|
||||
>
|
||||
<FederationTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.http')"
|
||||
icon="globe"
|
||||
data-tab-name="http"
|
||||
>
|
||||
<HTTPTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.job_queues')"
|
||||
icon="gears"
|
||||
data-tab-name="job_queues"
|
||||
>
|
||||
<JobQueuesTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.monitoring')"
|
||||
icon="chart-line"
|
||||
data-tab-name="monitoring"
|
||||
>
|
||||
<MonitoringTab />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:label="$t('admin_dash.tabs.other')"
|
||||
icon="ellipsis"
|
||||
data-tab-name="other"
|
||||
>
|
||||
<OtherTab />
|
||||
</div>
|
||||
</vertical-tab-switcher>
|
||||
</template>
|
||||
|
||||
<script src="./settings_modal_admin_content.js"></script>
|
||||
|
||||
<style src="./settings_modal_admin_content.scss" lang="scss"></style>
|
||||
<style lang="scss">
|
||||
.settings-admin-content {
|
||||
.setting-item {
|
||||
grid-template-columns: 1fr 3fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
.settings_tab-switcher {
|
||||
height: 100%;
|
||||
|
||||
[full-height="true"] {
|
||||
height: 100%
|
||||
}
|
||||
|
||||
.setting-item {
|
||||
margin: 1em 1em 1.4em;
|
||||
padding-bottom: 1.4em;
|
||||
|
||||
> div,
|
||||
> label {
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-multiple {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.option-list {
|
||||
margin: 0;
|
||||
margin-top: 0.5em;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.unavailable,
|
||||
.unavailable svg {
|
||||
color: var(--cRed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,6 @@
|
|||
<AppearanceTab />
|
||||
</div>
|
||||
<div
|
||||
:full-width="true"
|
||||
:label="$t('settings.layout')"
|
||||
icon="table-columns"
|
||||
data-tab-name="layout"
|
||||
|
|
@ -68,7 +67,6 @@
|
|||
</div>
|
||||
<div
|
||||
:label="$t('settings.filtering')"
|
||||
:full-width="true"
|
||||
icon="filter"
|
||||
data-tab-name="filtering"
|
||||
>
|
||||
|
|
@ -139,5 +137,3 @@
|
|||
</template>
|
||||
|
||||
<script src="./settings_modal_user_content.js"></script>
|
||||
|
||||
<style src="./settings_modal_user_content.scss" lang="scss"></style>
|
||||
|
|
|
|||
|
|
@ -237,7 +237,6 @@ const AppearanceTab = {
|
|||
return !window.IntersectionObserver
|
||||
},
|
||||
instanceWallpaper () {
|
||||
console.log(this.$store.state.instance.background)
|
||||
this.$store.state.instance.background
|
||||
},
|
||||
instanceWallpaperUsed () {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
.appearance-tab {
|
||||
margin: 1em;
|
||||
|
||||
h3 {
|
||||
border: none
|
||||
}
|
||||
|
|
@ -67,7 +69,7 @@
|
|||
aspect-ratio: 16 / 9;
|
||||
width: 16em;
|
||||
}
|
||||
|
||||
|
||||
img {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
|
@ -138,6 +140,7 @@
|
|||
border: 1px solid var(--border);
|
||||
margin-bottom: 0.5em;
|
||||
margin-top: 0;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.palettes {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
icon="table-columns"
|
||||
>
|
||||
<div
|
||||
class="setting-item"
|
||||
class="setting-section"
|
||||
:label="$t('settings.theme')"
|
||||
icon="paintbrush"
|
||||
>
|
||||
|
|
@ -161,13 +161,16 @@
|
|||
<div class="fun-monitor-neck button-default" />
|
||||
<div class="fun-monitor-display-bezel button-default">
|
||||
<div class="fun-monitor-display-screen input">
|
||||
<img
|
||||
v-if="backgroundPreview || user.background_image || instanceWallpaper"
|
||||
class="fun-monitor-display-screen-image"
|
||||
:src="backgroundPreview || user.background_image || instanceWallpaper"
|
||||
/>
|
||||
<div v-else class="wallpaper" />
|
||||
<div class="fun-monitor-display-screen-overlay input" />
|
||||
<img
|
||||
v-if="backgroundPreview || user.background_image || instanceWallpaper"
|
||||
class="fun-monitor-display-screen-image"
|
||||
:src="backgroundPreview || user.background_image || instanceWallpaper"
|
||||
>
|
||||
<div
|
||||
v-else
|
||||
class="wallpaper"
|
||||
/>
|
||||
<div class="fun-monitor-display-screen-overlay input" />
|
||||
<div
|
||||
v-if="backgroundUploading"
|
||||
class="fun-monitor-display-uploading"
|
||||
|
|
|
|||
|
|
@ -152,7 +152,6 @@ const ClutterTab = {
|
|||
},
|
||||
purgeExpiredFilters () {
|
||||
this.muteFiltersExpired.forEach(([id]) => {
|
||||
console.log(id)
|
||||
delete this.muteFiltersDraftObject[id]
|
||||
this.unsetPreference({ path: 'simple.muteFilters.' + id , value: null })
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="clutter-tab">
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.interface') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
<template>
|
||||
<div :label="$t('settings.posts')">
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.general') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<label for="default-vis">
|
||||
{{ $t('settings.default_vis') }}
|
||||
{{ ' ' }}
|
||||
<label
|
||||
class="setting-item "
|
||||
for="default-vis"
|
||||
>
|
||||
<span class="setting-label">
|
||||
<ProfileSettingIndicator :is-profile="true" />
|
||||
{{ $t('settings.default_vis') }}
|
||||
</span>
|
||||
<ScopeSelector
|
||||
class="scope-selector"
|
||||
class="scope-selector setting-control"
|
||||
:show-all="true"
|
||||
:user-default="$store.state.profileConfig.defaultScope"
|
||||
:initial-scope="$store.state.profileConfig.defaultScope"
|
||||
|
|
@ -16,7 +21,6 @@
|
|||
:unstyled="false"
|
||||
uns
|
||||
/>
|
||||
<ProfileSettingIndicator :is-profile="true" />
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
class="data-import-export-tab"
|
||||
:label="$t('settings.data_import_export_tab')"
|
||||
>
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.import_export.title') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,24 @@
|
|||
.developer-tab {
|
||||
.setting-list {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
.cache-buttons {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-column: 1 / 3;
|
||||
column-gap: 0.5em;
|
||||
margin: 0 5em;
|
||||
|
||||
.-mobile & {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
row-gap: 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dt {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
:label="$t('settings.developer')"
|
||||
class="developer-tab"
|
||||
>
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.version.title') }}</h3>
|
||||
<dl class="setting-list">
|
||||
<dt>{{ $t('settings.version.backend_version') }}</dt>
|
||||
|
|
@ -32,22 +32,6 @@
|
|||
{{ $t('settings.virtual_scrolling') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="clearAssetCache"
|
||||
>
|
||||
{{ $t('settings.clear_asset_cache') }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="clearEmojiCache"
|
||||
>
|
||||
{{ $t('settings.clear_emoji_cache') }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path="themeDebug"
|
||||
|
|
@ -64,6 +48,25 @@
|
|||
{{ $t('settings.force_theme_recompilation_debug') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<h4>{{ $t('settings.cache') }}</h4>
|
||||
<li>
|
||||
<div class="setting-item">
|
||||
<div class="cache-buttons">
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="clearAssetCache"
|
||||
>
|
||||
{{ $t('settings.clear_asset_cache') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="clearEmojiCache"
|
||||
>
|
||||
{{ $t('settings.clear_emoji_cache') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -217,7 +217,6 @@ const FilteringTab = {
|
|||
},
|
||||
purgeExpiredFilters () {
|
||||
this.muteFiltersExpired.forEach(([id]) => {
|
||||
console.log(id)
|
||||
delete this.muteFiltersDraftObject[id]
|
||||
this.unsetPreference({ path: 'simple.muteFilters.' + id , value: null })
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="filtering-tab">
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.filter.mute_filter') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
|
|
@ -14,19 +14,23 @@
|
|||
</ChoiceSetting>
|
||||
</li>
|
||||
<li>
|
||||
{{ $t('user_card.default_mute_expiration') }}
|
||||
<Select
|
||||
id="onMuteDefaultActionLv1"
|
||||
v-model="onMuteDefaultActionLv1"
|
||||
>
|
||||
<option
|
||||
v-for="option in muteBlockLv1Options"
|
||||
:key="option.key"
|
||||
:value="option.value"
|
||||
<span class="setting-item">
|
||||
<span class="setting-label">
|
||||
{{ $t('user_card.default_mute_expiration') }}
|
||||
</span>
|
||||
<Select
|
||||
id="onMuteDefaultActionLv1"
|
||||
v-model="onMuteDefaultActionLv1"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</Select>
|
||||
<option
|
||||
v-for="option in muteBlockLv1Options"
|
||||
:key="option.key"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</Select>
|
||||
</span>
|
||||
<ul
|
||||
v-if="onMuteDefaultActionLv1 === 'temporarily'"
|
||||
class="setting-list suboptions"
|
||||
|
|
@ -44,19 +48,24 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li v-if="blockExpirationSupported">
|
||||
{{ $t('user_card.default_block_expiration') }}
|
||||
<Select
|
||||
id="onBlockDefaultActionLv1"
|
||||
v-model="onBlockDefaultActionLv1"
|
||||
>
|
||||
<option
|
||||
v-for="option in muteBlockLv1Options"
|
||||
:key="option.key"
|
||||
:value="option.value"
|
||||
<span class="setting-item">
|
||||
<span class="setting-label">
|
||||
{{ $t('user_card.default_block_expiration') }}
|
||||
</span>
|
||||
<Select
|
||||
id="onBlockDefaultActionLv1"
|
||||
v-model="onBlockDefaultActionLv1"
|
||||
class="setting-control"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</Select>
|
||||
<option
|
||||
v-for="option in muteBlockLv1Options"
|
||||
:key="option.key"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</Select>
|
||||
</span>
|
||||
<ul
|
||||
v-if="onBlockDefaultActionLv1 === 'temporarily'"
|
||||
class="setting-list suboptions"
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.format_and_language') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<interface-language-switcher
|
||||
v-model="language"
|
||||
@update="val => language = val"
|
||||
>
|
||||
{{ $t('settings.interfaceLanguage') }}
|
||||
</interface-language-switcher>
|
||||
</li>
|
||||
<li>
|
||||
<interface-language-switcher
|
||||
v-model="emailLanguage"
|
||||
:profile="true"
|
||||
@update:model-value="updateProfile()"
|
||||
>
|
||||
{{ $t('settings.email_language') }}
|
||||
</interface-language-switcher>
|
||||
</li>
|
||||
<h4>{{ $t('settings.interfaceLanguage') }}</h4>
|
||||
<interface-language-switcher
|
||||
v-model="language"
|
||||
class="lang-selector"
|
||||
@update="val => language = val"
|
||||
/>
|
||||
<h4>
|
||||
{{ $t('settings.email_language') }}
|
||||
{{ ' ' }}
|
||||
<ProfileSettingIndicator :is-profile="true" />
|
||||
</h4>
|
||||
<interface-language-switcher
|
||||
v-model="emailLanguage"
|
||||
class="lang-selector"
|
||||
:profile="true"
|
||||
@update:model-value="updateProfile()"
|
||||
/>
|
||||
<li>
|
||||
<BooleanSetting path="useAbsoluteTimeFormat">
|
||||
{{ $t('settings.absolute_time_format') }}
|
||||
|
|
@ -47,26 +47,24 @@
|
|||
>
|
||||
{{ $t('settings.text_size') }}
|
||||
</UnitSetting>
|
||||
<div>
|
||||
<small>
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="settings.text_size_tip"
|
||||
tag="span"
|
||||
>
|
||||
<code>px</code>
|
||||
<code>rem</code>
|
||||
</i18n-t>
|
||||
<br>
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="settings.text_size_tip2"
|
||||
tag="span"
|
||||
>
|
||||
<code>14px</code>
|
||||
</i18n-t>
|
||||
</small>
|
||||
</div>
|
||||
<p class="sidenote">
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="settings.text_size_tip"
|
||||
tag="span"
|
||||
>
|
||||
<code>px</code>
|
||||
<code>rem</code>
|
||||
</i18n-t>
|
||||
<br>
|
||||
<i18n-t
|
||||
scope="global"
|
||||
keypath="settings.text_size_tip2"
|
||||
tag="span"
|
||||
>
|
||||
<code>14px</code>
|
||||
</i18n-t>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<FontControl
|
||||
|
|
@ -144,7 +142,9 @@
|
|||
class="setting-list"
|
||||
>
|
||||
<li class="select-multiple">
|
||||
<span class="label">{{ $t('settings.confirm_dialogs') }}</span>
|
||||
<h4 class="label">
|
||||
{{ $t('settings.confirm_dialogs') }}
|
||||
</h4>
|
||||
<ul class="option-list">
|
||||
<li>
|
||||
<BooleanSetting path="modalOnRepeat">
|
||||
|
|
@ -156,9 +156,10 @@
|
|||
{{ $t('settings.confirm_dialogs_unfollow') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<li
|
||||
v-if="!blockExpirationSupported"
|
||||
>
|
||||
<BooleanSetting
|
||||
v-if="!blockExpirationSupported"
|
||||
path="modalOnBlock"
|
||||
>
|
||||
{{ $t('settings.confirm_dialogs_block') }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div :label="$t('settings.layout')">
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.general') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div :label="$t('settings.notifications')">
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.notification_setting_annoyance') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
|
|
@ -12,11 +12,9 @@
|
|||
<BooleanSetting path="ignoreInactionableSeen">
|
||||
{{ $t('settings.notification_setting_ignore_inactionable_seen') }}
|
||||
</BooleanSetting>
|
||||
<div>
|
||||
<small>
|
||||
{{ $t('settings.notification_setting_ignore_inactionable_seen_tip') }}
|
||||
</small>
|
||||
</div>
|
||||
<p class="sidenote">
|
||||
{{ $t('settings.notification_setting_ignore_inactionable_seen_tip') }}
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
|
|
@ -28,7 +26,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.notification_setting_filters') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
|
|
@ -41,7 +39,10 @@
|
|||
</li>
|
||||
<li>
|
||||
<h4> {{ $t('settings.notification_visibility') }}</h4>
|
||||
<p v-if="expertLevel > 0">
|
||||
<p
|
||||
v-if="expertLevel > 0"
|
||||
class="sidenote"
|
||||
>
|
||||
{{ $t('settings.notification_setting_filters_chrome_push') }}
|
||||
</p>
|
||||
<ul class="setting-list two-column">
|
||||
|
|
@ -241,7 +242,7 @@
|
|||
|
||||
<div
|
||||
v-if="expertLevel > 0"
|
||||
class="setting-item"
|
||||
class="setting-section"
|
||||
>
|
||||
<h3>{{ $t('settings.notification_setting_privacy') }}</h3>
|
||||
<ul class="setting-list">
|
||||
|
|
@ -260,11 +261,12 @@
|
|||
>
|
||||
{{ $t('settings.enable_web_push_always_show') }}
|
||||
</BooleanSetting>
|
||||
<div :class="{ faint: !mergedConfig.webPushNotifications }">
|
||||
<small>
|
||||
{{ $t('settings.enable_web_push_always_show_tip') }}
|
||||
</small>
|
||||
</div>
|
||||
<p
|
||||
:class="{ faint: !mergedConfig.webPushNotifications }"
|
||||
class="sidenote"
|
||||
>
|
||||
{{ $t('settings.enable_web_push_always_show_tip') }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -279,10 +281,12 @@
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<p>{{ $t('settings.notification_mutes') }}</p>
|
||||
<p>{{ $t('settings.notification_blocks') }}</p>
|
||||
</div>
|
||||
<p class="sidenote">
|
||||
<ul>
|
||||
<li>{{ $t('settings.notification_mutes') }}</li>
|
||||
<li>{{ $t('settings.notification_blocks') }}</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
.old-theme-tab {
|
||||
min-width: var(--themeEditorMinWidth, fit-content);
|
||||
margin: 1em;
|
||||
|
||||
.deprecation-warning {
|
||||
padding: 0.5em;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="posts-tab">
|
||||
<div class="setting-item">
|
||||
<div class="setting-section">
|
||||
<h3>{{ $t('settings.posts_appearance') }}</h3>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.profile-tab {
|
||||
// overriding global for better look
|
||||
.setting-item.profile-edit {
|
||||
.setting-section.profile-edit {
|
||||
margin: 0;
|
||||
|
||||
h2 {
|
||||
|
|
@ -11,5 +11,28 @@
|
|||
padding: 1.2em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.setting-item {
|
||||
.custom-boolean-setting {
|
||||
display: grid;
|
||||
grid-template-columns: subgrid;
|
||||
|
||||
.label {
|
||||
grid-area: label;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.-mobile & {
|
||||
.label {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-indicator {
|
||||
grid-area: control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue