aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/post_status_form/post_status_form.js1
-rw-r--r--src/components/settings_modal/helpers/boolean_setting.js15
-rw-r--r--src/components/settings_modal/helpers/boolean_setting.vue4
-rw-r--r--src/components/settings_modal/helpers/choice_setting.js15
-rw-r--r--src/components/settings_modal/helpers/choice_setting.vue2
-rw-r--r--src/components/settings_modal/helpers/server_side_indicator.vue51
-rw-r--r--src/components/settings_modal/helpers/shared_computed_object.js9
-rw-r--r--src/components/settings_modal/settings_modal.js11
-rw-r--r--src/components/settings_modal/settings_modal.scss7
-rw-r--r--src/components/settings_modal/settings_modal.vue6
-rw-r--r--src/components/settings_modal/tabs/filtering_tab.vue56
-rw-r--r--src/components/settings_modal/tabs/general_tab.js11
-rw-r--r--src/components/settings_modal/tabs/general_tab.vue223
-rw-r--r--src/components/settings_modal/tabs/notifications_tab.js8
-rw-r--r--src/components/settings_modal/tabs/notifications_tab.vue81
-rw-r--r--src/components/settings_modal/tabs/profile_tab.js23
-rw-r--r--src/components/settings_modal/tabs/profile_tab.vue121
-rw-r--r--src/i18n/en.json10
-rw-r--r--src/main.js2
-rw-r--r--src/modules/config.js5
-rw-r--r--src/modules/serverSideConfig.js137
-rw-r--r--src/services/entity_normalizer/entity_normalizer.service.js1
22 files changed, 575 insertions, 224 deletions
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index fe07309f..9d7bbd75 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -117,6 +117,7 @@ const PostStatusForm = {
? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope
+ // const { defaultNSFW: sensitiveByDefault } = this.$store.state.serverSideConfig
const { postContentType: contentType, sensitiveByDefault } = this.$store.getters.mergedConfig
return {
diff --git a/src/components/settings_modal/helpers/boolean_setting.js b/src/components/settings_modal/helpers/boolean_setting.js
index 5c52f697..353e551c 100644
--- a/src/components/settings_modal/helpers/boolean_setting.js
+++ b/src/components/settings_modal/helpers/boolean_setting.js
@@ -1,14 +1,17 @@
import { get, set } from 'lodash'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import ModifiedIndicator from './modified_indicator.vue'
+import ServerSideIndicator from './server_side_indicator.vue'
export default {
components: {
Checkbox,
- ModifiedIndicator
+ ModifiedIndicator,
+ ServerSideIndicator
},
props: [
'path',
- 'disabled'
+ 'disabled',
+ 'expert'
],
computed: {
pathDefault () {
@@ -26,8 +29,14 @@ export default {
defaultState () {
return get(this.$parent, this.pathDefault)
},
+ isServerSide () {
+ return this.path.startsWith('serverSide_')
+ },
isChanged () {
- return this.state !== this.defaultState
+ return !this.path.startsWith('serverSide_') && this.state !== this.defaultState
+ },
+ matchesExpertLevel () {
+ return (this.expert || 0) <= this.$parent.expertLevel
}
},
methods: {
diff --git a/src/components/settings_modal/helpers/boolean_setting.vue b/src/components/settings_modal/helpers/boolean_setting.vue
index c3ee6583..e0d825f2 100644
--- a/src/components/settings_modal/helpers/boolean_setting.vue
+++ b/src/components/settings_modal/helpers/boolean_setting.vue
@@ -1,5 +1,6 @@
<template>
<label
+ v-if="matchesExpertLevel"
class="BooleanSetting"
>
<Checkbox
@@ -13,8 +14,7 @@
>
<slot />
</span>
- <ModifiedIndicator :changed="isChanged" />
- </Checkbox>
+ <ModifiedIndicator :changed="isChanged" /><ServerSideIndicator :server-side="isServerSide" /> </Checkbox>
</label>
</template>
diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js
index a15f6bac..4677d4c1 100644
--- a/src/components/settings_modal/helpers/choice_setting.js
+++ b/src/components/settings_modal/helpers/choice_setting.js
@@ -1,15 +1,18 @@
import { get, set } from 'lodash'
import Select from 'src/components/select/select.vue'
import ModifiedIndicator from './modified_indicator.vue'
+import ServerSideIndicator from './server_side_indicator.vue'
export default {
components: {
Select,
- ModifiedIndicator
+ ModifiedIndicator,
+ ServerSideIndicator
},
props: [
'path',
'disabled',
- 'options'
+ 'options',
+ 'expert'
],
computed: {
pathDefault () {
@@ -27,8 +30,14 @@ export default {
defaultState () {
return get(this.$parent, this.pathDefault)
},
+ isServerSide () {
+ return this.path.startsWith('serverSide_')
+ },
isChanged () {
- return this.state !== this.defaultState
+ return !this.path.startsWith('serverSide_') && this.state !== this.defaultState
+ },
+ matchesExpertLevel () {
+ return (this.expert || 0) <= this.$parent.expertLevel
}
},
methods: {
diff --git a/src/components/settings_modal/helpers/choice_setting.vue b/src/components/settings_modal/helpers/choice_setting.vue
index fa17661b..54f5d0a7 100644
--- a/src/components/settings_modal/helpers/choice_setting.vue
+++ b/src/components/settings_modal/helpers/choice_setting.vue
@@ -1,5 +1,6 @@
<template>
<label
+ v-if="matchesExpertLevel"
class="ChoiceSetting"
>
<slot />
@@ -18,6 +19,7 @@
</option>
</Select>
<ModifiedIndicator :changed="isChanged" />
+ <ServerSideIndicator :server-side="isServerSide" />
</label>
</template>
diff --git a/src/components/settings_modal/helpers/server_side_indicator.vue b/src/components/settings_modal/helpers/server_side_indicator.vue
new file mode 100644
index 00000000..143a86a1
--- /dev/null
+++ b/src/components/settings_modal/helpers/server_side_indicator.vue
@@ -0,0 +1,51 @@
+<template>
+ <span
+ v-if="serverSide"
+ class="ServerSideIndicator"
+ >
+ <Popover
+ trigger="hover"
+ >
+ <template v-slot:trigger>
+ &nbsp;
+ <FAIcon
+ icon="server"
+ :aria-label="$t('settings.setting_server_side')"
+ />
+ </template>
+ <template v-slot:content>
+ <div class="serverside-tooltip">
+ {{ $t('settings.setting_server_side') }}
+ </div>
+ </template>
+ </Popover>
+ </span>
+</template>
+
+<script>
+import Popover from 'src/components/popover/popover.vue'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { faServer } from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+ faServer
+)
+
+export default {
+ components: { Popover },
+ props: ['serverSide']
+}
+</script>
+
+<style lang="scss">
+.ServerSideIndicator {
+ display: inline-block;
+ position: relative;
+
+ .serverside-tooltip {
+ margin: 0.5em 1em;
+ min-width: 10em;
+ text-align: center;
+ }
+}
+</style>
diff --git a/src/components/settings_modal/helpers/shared_computed_object.js b/src/components/settings_modal/helpers/shared_computed_object.js
index 2c833c0c..12431dca 100644
--- a/src/components/settings_modal/helpers/shared_computed_object.js
+++ b/src/components/settings_modal/helpers/shared_computed_object.js
@@ -1,4 +1,5 @@
import { defaultState as configDefaultState } from 'src/modules/config.js'
+import { defaultState as serverSideConfigDefaultState } from 'src/modules/serverSideConfig.js'
const SharedComputedObject = () => ({
user () {
@@ -22,6 +23,14 @@ const SharedComputedObject = () => ({
}
}])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
+ ...Object.keys(serverSideConfigDefaultState)
+ .map(key => ['serverSide_' + key, {
+ get () { return this.$store.state.serverSideConfig[key] },
+ set (value) {
+ this.$store.dispatch('setServerSideOption', { name: key, value })
+ }
+ }])
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
// Special cases (need to transform values or perform actions first)
useStreamingApi: {
get () { return this.$store.getters.mergedConfig.useStreamingApi },
diff --git a/src/components/settings_modal/settings_modal.js b/src/components/settings_modal/settings_modal.js
index 04043483..82ea410e 100644
--- a/src/components/settings_modal/settings_modal.js
+++ b/src/components/settings_modal/settings_modal.js
@@ -3,6 +3,7 @@ import PanelLoading from 'src/components/panel_loading/panel_loading.vue'
import AsyncComponentError from 'src/components/async_component_error/async_component_error.vue'
import getResettableAsyncComponent from 'src/services/resettable_async_component.js'
import Popover from '../popover/popover.vue'
+import Checkbox from 'src/components/checkbox/checkbox.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { cloneDeep } from 'lodash'
import {
@@ -51,6 +52,7 @@ const SettingsModal = {
components: {
Modal,
Popover,
+ Checkbox,
SettingsModalContent: getResettableAsyncComponent(
() => import('./settings_modal_content.vue'),
{
@@ -159,6 +161,15 @@ const SettingsModal = {
},
modalPeeked () {
return this.$store.state.interface.settingsModalState === 'minimized'
+ },
+ expertLevel: {
+ get () {
+ return this.$store.state.config.expertLevel > 0
+ },
+ set (value) {
+ console.log(value)
+ this.$store.dispatch('setOption', { name: 'expertLevel', value: value ? 1 : 0 })
+ }
}
}
}
diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss
index 90446b36..fb466f2f 100644
--- a/src/components/settings_modal/settings_modal.scss
+++ b/src/components/settings_modal/settings_modal.scss
@@ -48,4 +48,11 @@
}
}
}
+
+ .settings-footer {
+ display: flex;
+ >* {
+ margin-right: 0.5em;
+ }
+ }
}
diff --git a/src/components/settings_modal/settings_modal.vue b/src/components/settings_modal/settings_modal.vue
index 583c2ecc..1805c77f 100644
--- a/src/components/settings_modal/settings_modal.vue
+++ b/src/components/settings_modal/settings_modal.vue
@@ -53,7 +53,7 @@
<div class="panel-body">
<SettingsModalContent v-if="modalOpenedOnce" />
</div>
- <div class="panel-footer">
+ <div class="panel-footer settings-footer">
<Popover
class="export"
trigger="click"
@@ -108,6 +108,10 @@
</div>
</template>
</Popover>
+
+ <Checkbox v-model="expertLevel">
+ {{ $t("settings.expert_mode") }}
+ </Checkbox>
</div>
</div>
</Modal>
diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue
index a7e30ce2..81e9543b 100644
--- a/src/components/settings_modal/tabs/filtering_tab.vue
+++ b/src/components/settings_modal/tabs/filtering_tab.vue
@@ -21,6 +21,7 @@
</li>
<li>
<BooleanSetting
+ v-if="user"
:disabled="hideFilteredStatuses"
path="hideMutedThreads"
>
@@ -29,6 +30,7 @@
</li>
<li>
<BooleanSetting
+ v-if="user"
:disabled="hideFilteredStatuses"
path="hideMutedPosts"
>
@@ -38,6 +40,12 @@
</ul>
</li>
<li>
+ <BooleanSetting
+ path="hidePostStats"
+ expert="1"
+ >
+ </li>
+ <li>
<BooleanSetting path="muteBotStatuses">
{{ $t('settings.mute_bot_posts') }}
</BooleanSetting>
@@ -53,6 +61,7 @@
</BooleanSetting>
</li>
<ChoiceSetting
+ v-if="user"
id="replyVisibility"
path="replyVisibility"
:options="replyVisibilityOptions"
@@ -69,7 +78,7 @@
<div>{{ $t('settings.filtering_explanation') }}</div>
</li>
<h3>{{ $t('settings.attachments') }}</h3>
- <li>
+ <li v-if="expertLevel > 0">
<label for="maxThumbnails">
{{ $t('settings.max_thumbnails') }}
</label>
@@ -94,7 +103,10 @@
</li>
</ul>
</div>
- <div class="setting-item">
+ <div
+ v-if="expertLevel > 0"
+ class="setting-item"
+ >
<h2>{{ $t('settings.user_profiles') }}</h2>
<ul class="setting-list">
<li>
@@ -104,46 +116,6 @@
</li>
</ul>
</div>
- <div class="setting-item">
- <h2>{{ $t('settings.notifications') }}</h2>
- <ul class="setting-list">
- <li class="select-multiple">
- <span class="label">{{ $t('settings.notification_visibility') }}</span>
- <ul class="option-list">
- <li>
- <BooleanSetting path="notificationVisibility.likes">
- {{ $t('settings.notification_visibility_likes') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="notificationVisibility.repeats">
- {{ $t('settings.notification_visibility_repeats') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="notificationVisibility.follows">
- {{ $t('settings.notification_visibility_follows') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="notificationVisibility.mentions">
- {{ $t('settings.notification_visibility_mentions') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="notificationVisibility.moves">
- {{ $t('settings.notification_visibility_moves') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="notificationVisibility.emojiReactions">
- {{ $t('settings.notification_visibility_emoji_reactions') }}
- </BooleanSetting>
- </li>
- </ul>
- </li>
- </ul>
- </div>
</div>
</template>
<script src="./filtering_tab.js"></script>
diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js
index 952c328d..fe7deb6e 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -1,8 +1,10 @@
import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue'
+import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
+import ServerSideIndicator from '../helpers/server_side_indicator.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faGlobe
@@ -37,7 +39,9 @@ const GeneralTab = {
components: {
BooleanSetting,
ChoiceSetting,
- InterfaceLanguageSwitcher
+ InterfaceLanguageSwitcher,
+ ScopeSelector,
+ ServerSideIndicator
},
computed: {
postFormats () {
@@ -57,6 +61,11 @@ const GeneralTab = {
},
instanceShoutboxPresent () { return this.$store.state.instance.shoutAvailable },
...SharedComputedObject()
+ },
+ methods: {
+ changeDefaultScope (value) {
+ this.$store.dispatch('setServerSideOption', { name: 'defaultScope', value })
+ }
}
}
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index eba3b268..ceb61655 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -45,26 +45,42 @@
</ul>
</li>
<li>
- <BooleanSetting path="useStreamingApi">
+ <BooleanSetting
+ path="useStreamingApi"
+ expert="1"
+ >
{{ $t('settings.useStreamingApi') }}
- <br>
- <small>
- {{ $t('settings.useStreamingApiWarning') }}
- </small>
</BooleanSetting>
</li>
<li>
- <BooleanSetting path="virtualScrolling">
+ <BooleanSetting
+ path="virtualScrolling"
+ expert="1"
+ >
{{ $t('settings.virtual_scrolling') }}
</BooleanSetting>
</li>
<li>
- <BooleanSetting path="autohideFloatingPostButton">
+ <BooleanSetting
+ path="alwaysShowNewPostButton"
+ expert="1"
+ >
+ {{ $t('settings.always_show_post_button') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting
+ path="autohideFloatingPostButton"
+ expert="1"
+ >
{{ $t('settings.autohide_floating_post_button') }}
</BooleanSetting>
</li>
<li v-if="instanceShoutboxPresent">
- <BooleanSetting path="hideShoutbox">
+ <BooleanSetting
+ path="hideShoutbox"
+ expert="1"
+ >
{{ $t('settings.hide_shoutbox') }}
</BooleanSetting>
</li>
@@ -79,13 +95,28 @@
</BooleanSetting>
</li>
<li>
- <BooleanSetting path="emojiReactionsOnTimeline">
+ <BooleanSetting
+ path="emojiReactionsOnTimeline"
+ expert="1"
+ >
{{ $t('settings.emoji_reactions_on_timeline') }}
</BooleanSetting>
</li>
+ <li>
+ <BooleanSetting
+ v-if="user"
+ path="serverSide_stripRichContent"
+ expert="1"
+ >
+ {{ $t('settings.no_rich_text_description') }}
+ </BooleanSetting>
+ </li>
<h3>{{ $t('settings.attachments') }}</h3>
<li>
- <BooleanSetting path="useContainFit">
+ <BooleanSetting
+ path="useContainFit"
+ expert="1"
+ >
{{ $t('settings.use_contain_fit') }}
</BooleanSetting>
</li>
@@ -98,6 +129,7 @@
<li>
<BooleanSetting
path="preloadImage"
+ expert="1"
:disabled="!hideNsfw"
>
{{ $t('settings.preload_images') }}
@@ -106,6 +138,7 @@
<li>
<BooleanSetting
path="useOneClickNsfw"
+ expert="1"
:disabled="!hideNsfw"
>
{{ $t('settings.use_one_click_nsfw') }}
@@ -113,7 +146,10 @@
</li>
</ul>
<li>
- <BooleanSetting path="loopVideo">
+ <BooleanSetting
+ path="loopVideo"
+ expert="1"
+ >
{{ $t('settings.loop_video') }}
</BooleanSetting>
<ul
@@ -123,6 +159,7 @@
<li>
<BooleanSetting
path="loopVideoSilentOnly"
+ expert="1"
:disabled="!loopVideo || !loopSilentAvailable"
>
{{ $t('settings.loop_video_silent_only') }}
@@ -137,21 +174,14 @@
</ul>
</li>
<li>
- <BooleanSetting path="playVideosInModal">
+ <BooleanSetting
+ path="playVideosInModal"
+ expert="1"
+ >
{{ $t('settings.play_videos_in_modal') }}
</BooleanSetting>
</li>
- <h3>{{ $t('settings.fun') }}</h3>
- <li>
- <BooleanSetting path="greentext">
- {{ $t('settings.greentext') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="mentionLinkShowYous">
- {{ $t('settings.show_yous') }}
- </BooleanSetting>
- </li>
+ <h3>{{ $t('settings.mention_links') }}</h3>
<li>
<ChoiceSetting
id="mentionLinkDisplay"
@@ -164,47 +194,103 @@
<ul
class="setting-list suboptions"
>
- <li
- v-if="mentionLinkDisplay === 'short'"
- >
- <BooleanSetting path="mentionLinkShowTooltip">
+ <li v-if="mentionLinkDisplay === 'short'">
+ <BooleanSetting
+ path="mentionLinkShowTooltip"
+ expert="1"
+ >
{{ $t('settings.mention_link_show_tooltip') }}
</BooleanSetting>
</li>
- <li>
- <BooleanSetting path="useAtIcon">
- {{ $t('settings.use_at_icon') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="mentionLinkShowAvatar">
- {{ $t('settings.mention_link_show_avatar') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="mentionLinkFadeDomain">
- {{ $t('settings.mention_link_fade_domain') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="mentionLinkBoldenYou">
- {{ $t('settings.mention_link_bolden_you') }}
- </BooleanSetting>
- </li>
</ul>
+ <li>
+ <BooleanSetting
+ path="useAtIcon"
+ expert="1"
+ >
+ {{ $t('settings.use_at_icon') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="mentionLinkShowAvatar">
+ {{ $t('settings.mention_link_show_avatar') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting
+ path="mentionLinkFadeDomain"
+ expert="1"
+ >
+ {{ $t('settings.mention_link_fade_domain') }}
+ </BooleanSetting>
+ </li>
+ <li v-if="user">
+ <BooleanSetting
+ path="mentionLinkBoldenYou"
+ expert="1"
+ >
+ {{ $t('settings.mention_link_bolden_you') }}
+ </BooleanSetting>
+ </li>
+ <h3 v-if="expertLevel > 0">
+ {{ $t('settings.fun') }}
+ </h3>
+ <li>
+ <BooleanSetting
+ path="greentext"
+ expert="1"
+ >
+ {{ $t('settings.greentext') }}
+ </BooleanSetting>
+ </li>
+ <li v-if="user">
+ <BooleanSetting
+ path="mentionLinkShowYous"
+ expert="1"
+ >
+ {{ $t('settings.show_yous') }}
+ </BooleanSetting>
+ </li>
</ul>
</div>
- <div class="setting-item">
+ <div
+ v-if="user"
+ class="setting-item"
+ >
<h2>{{ $t('settings.composing') }}</h2>
<ul class="setting-list">
<li>
- <BooleanSetting path="scopeCopy">
+ <label for="default-vis">
+ {{ $t('settings.default_vis') }} <ServerSideIndicator :server-side="true" />
+ <ScopeSelector
+ class="scope-selector"
+ :show-all="true"
+ :user-default="serverSide_defaultScope"
+ :initial-scope="serverSide_defaultScope"
+ :on-scope-change="changeDefaultScope"
+ />
+ </label>
+ </li>
+ <li>
+ <!-- <BooleanSetting path="serverSide_defaultNSFW"> -->
+ <BooleanSetting path="sensitiveByDefault">
+ {{ $t('settings.sensitive_by_default') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting
+ path="scopeCopy"
+ expert="1"
+ >
{{ $t('settings.scope_copy') }}
</BooleanSetting>
</li>
<li>
- <BooleanSetting path="alwaysShowSubjectInput">
+ <BooleanSetting
+ path="alwaysShowSubjectInput"
+ expert="1"
+ >
{{ $t('settings.subject_input_always_show') }}
</BooleanSetting>
</li>
@@ -213,6 +299,7 @@
id="subjectLineBehavior"
path="subjectLineBehavior"
:options="subjectLineOptions"
+ expert="1"
>
{{ $t('settings.subject_line_behavior') }}
</ChoiceSetting>
@@ -227,43 +314,39 @@
</ChoiceSetting>
</li>
<li>
- <BooleanSetting path="minimalScopesMode">
+ <BooleanSetting
+ path="minimalScopesMode"
+ expert="1"
+ >
{{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting>
</li>
<li>
- <BooleanSetting path="sensitiveByDefault">
- {{ $t('settings.sensitive_by_default') }}
- </BooleanSetting>
- </li>
- <li>
- <BooleanSetting path="alwaysShowNewPostButton">
+ <BooleanSetting
+ path="alwaysShowNewPostButton"
+ expert="1"
+ >
{{ $t('settings.always_show_post_button') }}
</BooleanSetting>
</li>
<li>
- <BooleanSetting path="autohideFloatingPostButton">
+ <BooleanSetting
+ path="autohideFloatingPostButton"
+ expert="1"
+ >
{{ $t('settings.autohide_floating_post_button') }}
</BooleanSetting>
</li>
<li>
- <BooleanSetting path="padEmoji">
+ <BooleanSetting
+ path="padEmoji"
+ expert="1"
+ >
{{ $t('settings.pad_emoji') }}
</BooleanSetting>
</li>
</ul>
</div>
-
- <div class="setting-item">
- <h2>{{ $t('settings.notifications') }}</h2>
- <ul class="setting-list">
- <li>
- <BooleanSetting path="webPushNotifications">
- {{ $t('settings.enable_web_push_notifications') }}
- </BooleanSetting>
- </li>
- </ul>
- </div>
</div>
</template>
diff --git a/src/components/settings_modal/tabs/notifications_tab.js b/src/components/settings_modal/tabs/notifications_tab.js
index 3e44c95d..3c6ab87f 100644
--- a/src/components/settings_modal/tabs/notifications_tab.js
+++ b/src/components/settings_modal/tabs/notifications_tab.js
@@ -1,4 +1,5 @@
-import Checkbox from 'src/components/checkbox/checkbox.vue'
+import BooleanSetting from '../helpers/boolean_setting.vue'
+import SharedComputedObject from '../helpers/shared_computed_object.js'
const NotificationsTab = {
data () {
@@ -9,12 +10,13 @@ const NotificationsTab = {
}
},
components: {
- Checkbox
+ BooleanSetting
},
computed: {
user () {
return this.$store.state.users.currentUser
- }
+ },
+ ...SharedComputedObject()
},
methods: {
updateNotificationSettings () {
diff --git a/src/components/settings_modal/tabs/notifications_tab.vue b/src/components/settings_modal/tabs/notifications_tab.vue
index 7e0568ea..86be6095 100644
--- a/src/components/settings_modal/tabs/notifications_tab.vue
+++ b/src/components/settings_modal/tabs/notifications_tab.vue
@@ -2,30 +2,77 @@
<div :label="$t('settings.notifications')">
<div class="setting-item">
<h2>{{ $t('settings.notification_setting_filters') }}</h2>
- <p>
- <Checkbox v-model="notificationSettings.block_from_strangers">
- {{ $t('settings.notification_setting_block_from_strangers') }}
- </Checkbox>
- </p>
+ <ul class="setting-list">
+ <li>
+ <BooleanSetting path="serverSide_blockNotificationsFromStrangers">
+ {{ $t('settings.notification_setting_block_from_strangers') }}
+ </BooleanSetting>
+ </li>
+ <li class="select-multiple">
+ <span class="label">{{ $t('settings.notification_visibility') }}</span>
+ <ul class="option-list">
+ <li>
+ <BooleanSetting path="notificationVisibility.likes">
+ {{ $t('settings.notification_visibility_likes') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="notificationVisibility.repeats">
+ {{ $t('settings.notification_visibility_repeats') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="notificationVisibility.follows">
+ {{ $t('settings.notification_visibility_follows') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="notificationVisibility.mentions">
+ {{ $t('settings.notification_visibility_mentions') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="notificationVisibility.moves">
+ {{ $t('settings.notification_visibility_moves') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="notificationVisibility.emojiReactions">
+ {{ $t('settings.notification_visibility_emoji_reactions') }}
+ </BooleanSetting>
+ </li>
+ </ul>
+ </li>
+ </ul>
</div>
- <div class="setting-item">
+ <div
+ v-if="expertLevel > 0"
+ class="setting-item"
+ >
<h2>{{ $t('settings.notification_setting_privacy') }}</h2>
- <p>
- <Checkbox v-model="notificationSettings.hide_notification_contents">
- {{ $t('settings.notification_setting_hide_notification_contents') }}
- </Checkbox>
- </p>
+ <ul class="setting-list">
+ <li>
+ <BooleanSetting
+ path="webPushNotifications"
+ expert="1"
+ >
+ {{ $t('settings.enable_web_push_notifications') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting
+ path="serverSide_webPushHideContents"
+ expert="1"
+ >
+ {{ $t('settings.notification_setting_hide_notification_contents') }}
+ </BooleanSetting>
+ </li>
+ </ul>
</div>
<div class="setting-item">
<p>{{ $t('settings.notification_mutes') }}</p>
<p>{{ $t('settings.notification_blocks') }}</p>
- <button
- class="btn button-default"
- @click="updateNotificationSettings"
- >
- {{ $t('settings.save') }}
- </button>
</div>
</div>
</template>
diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js
index 64079fcd..bee8a7bb 100644
--- a/src/components/settings_modal/tabs/profile_tab.js
+++ b/src/components/settings_modal/tabs/profile_tab.js
@@ -8,6 +8,9 @@ import EmojiInput from 'src/components/emoji_input/emoji_input.vue'
import suggestor from 'src/components/emoji_input/suggestor.js'
import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
+import BooleanSetting from '../helpers/boolean_setting.vue'
+import SharedComputedObject from '../helpers/shared_computed_object.js'
+
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faTimes,
@@ -27,18 +30,10 @@ const ProfileTab = {
newName: this.$store.state.users.currentUser.name_unescaped,
newBio: unescape(this.$store.state.users.currentUser.description),
newLocked: this.$store.state.users.currentUser.locked,
- newNoRichText: this.$store.state.users.currentUser.no_rich_text,
- newDefaultScope: this.$store.state.users.currentUser.default_scope,
newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })),
- hideFollows: this.$store.state.users.currentUser.hide_follows,
- hideFollowers: this.$store.state.users.currentUser.hide_followers,
- hideFollowsCount: this.$store.state.users.currentUser.hide_follows_count,
- hideFollowersCount: this.$store.state.users.currentUser.hide_followers_count,
showRole: this.$store.state.users.currentUser.show_role,
role: this.$store.state.users.currentUser.role,
- discoverable: this.$store.state.users.currentUser.discoverable,
bot: this.$store.state.users.currentUser.bot,
- allowFollowingMove: this.$store.state.users.currentUser.allow_following_move,
pickAvatarBtnVisible: true,
bannerUploading: false,
backgroundUploading: false,
@@ -54,12 +49,14 @@ const ProfileTab = {
EmojiInput,
Autosuggest,
ProgressButton,
- Checkbox
+ Checkbox,
+ BooleanSetting
},
computed: {
user () {
return this.$store.state.users.currentUser
},
+ ...SharedComputedObject(),
emojiUserSuggestor () {
return suggestor({
emoji: [
@@ -123,15 +120,7 @@ const ProfileTab = {
/* eslint-disable camelcase */
display_name: this.newName,
fields_attributes: this.newFields.filter(el => el != null),
- default_scope: this.newDefaultScope,
- no_rich_text: this.newNoRichText,
- hide_follows: this.hideFollows,
- hide_followers: this.hideFollowers,
- discoverable: this.discoverable,
bot: this.bot,
- allow_following_move: this.allowFollowingMove,
- hide_follows_count: this.hideFollowsCount,
- hide_followers_count: this.hideFollowersCount,
show_role: this.showRole
/* eslint-enable camelcase */
} }).then((user) => {
diff --git a/src/components/settings_modal/tabs/profile_tab.vue b/src/components/settings_modal/tabs/profile_tab.vue
index bb3c301d..e00f6e5b 100644
--- a/src/components/settings_modal/tabs/profile_tab.vue
+++ b/src/components/settings_modal/tabs/profile_tab.vue
@@ -25,61 +25,6 @@
class="bio resize-height"
/>
</EmojiInput>
- <p>
- <Checkbox v-model="newLocked">
- {{ $t('settings.lock_account_description') }}
- </Checkbox>
- </p>
- <div>
- <label for="default-vis">{{ $t('settings.default_vis') }}</label>
- <div
- id="default-vis"
- class="visibility-tray"
- >
- <scope-selector
- :show-all="true"
- :user-default="newDefaultScope"
- :initial-scope="newDefaultScope"
- :on-scope-change="changeVis"
- />
- </div>
- </div>
- <p>
- <Checkbox v-model="newNoRichText">
- {{ $t('settings.no_rich_text_description') }}
- </Checkbox>
- </p>
- <p>
- <Checkbox v-model="hideFollows">
- {{ $t('settings.hide_follows_description') }}
- </Checkbox>
- </p>
- <p class="setting-subitem">
- <Checkbox
- v-model="hideFollowsCount"
- :disabled="!hideFollows"
- >
- {{ $t('settings.hide_follows_count_description') }}
- </Checkbox>
- </p>
- <p>
- <Checkbox v-model="hideFollowers">
- {{ $t('settings.hide_followers_description') }}
- </Checkbox>
- </p>
- <p class="setting-subitem">
- <Checkbox
- v-model="hideFollowersCount"
- :disabled="!hideFollowers"
- >
- {{ $t('settings.hide_followers_count_description') }}
- </Checkbox>
- </p>
- <p>
- <Checkbox v-model="allowFollowingMove">
- {{ $t('settings.allow_following_move') }}
- </Checkbox>
- </p>
<p v-if="role === 'admin' || role === 'moderator'">
<Checkbox v-model="showRole">
<template v-if="role === 'admin'">
@@ -90,11 +35,6 @@
</template>
</Checkbox>
</p>
- <p>
- <Checkbox v-model="discoverable">
- {{ $t('settings.discoverable') }}
- </Checkbox>
- </p>
<div v-if="maxFields > 0">
<p>{{ $t('settings.profile_fields.label') }}</p>
<div
@@ -269,6 +209,67 @@
{{ $t('settings.save') }}
</button>
</div>
+ <div class="setting-item">
+ <h2>{{ $t('settings.account_privacy') }}</h2>
+ <ul class="setting-list">
+ <li>
+ <BooleanSetting path="serverSide_locked">
+ {{ $t('settings.lock_account_description') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="serverSide_discoverable">
+ {{ $t('settings.discoverable') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="serverSide_allowFollowingMove">
+ {{ $t('settings.allow_following_move') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="serverSide_hideFavorites">
+ {{ $t('settings.hide_favorites_description') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="serverSide_hideFollowers">
+ {{ $t('settings.hide_followers_description') }}
+ </BooleanSetting>
+ <ul
+ class="setting-list suboptions"
+ :class="[{disabled: !serverSide_hideFollowers}]"
+ >
+ <li>
+ <BooleanSetting
+ path="serverSide_hideFollowersCount"
+ :disabled="!serverSide_hideFollowers"
+ >
+ {{ $t('settings.hide_followers_count_description') }}
+ </BooleanSetting>
+ </li>
+ </ul>
+ </li>
+ <li>
+ <BooleanSetting path="serverSide_hideFollows">
+ {{ $t('settings.hide_follows_description') }}
+ </BooleanSetting>
+ <ul
+ class="setting-list suboptions"
+ :class="[{disabled: !serverSide_hideFollows}]"
+ >
+ <li>
+ <BooleanSetting
+ path="serverSide_hideFollowsCount"
+ :disabled="!serverSide_hideFollows"
+ >
+ {{ $t('settings.hide_follows_count_description') }}
+ </BooleanSetting>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </div>
</div>
</template>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 61087ec2..61dd2538 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -259,11 +259,14 @@
},
"settings": {
"app_name": "App name",
+ "expert_mode": "Show advanced",
"save": "Save changes",
"security": "Security",
"setting_changed": "Setting is different from default",
+ "setting_server_side": "This setting is tied to your profile and affects all sessions and clients",
"enter_current_password_to_confirm": "Enter your current password to confirm your identity",
"post_look_feel": "Posts Look & Feel",
+ "mention_links": "Mention links",
"mfa": {
"otp": "OTP",
"setup_otp": "Setup OTP",
@@ -402,6 +405,7 @@
"name": "Label",
"value": "Content"
},
+ "account_privacy": "Privacy",
"use_contain_fit": "Don't crop the attachment in thumbnails",
"name": "Name",
"name_bio": "Name & bio",
@@ -419,6 +423,7 @@
"no_rich_text_description": "Strip rich text formatting from all posts",
"no_blocks": "No blocks",
"no_mutes": "No mutes",
+ "hide_favorites_description": "Don't show list of my favorites (people still get notified)",
"hide_follows_description": "Don't show who I'm following",
"hide_followers_description": "Don't show who's following me",
"hide_follows_count_description": "Don't show follow count",
@@ -432,7 +437,7 @@
"valid_until": "Valid until",
"revoke_token": "Revoke",
"panelRadius": "Panels",
- "pause_on_unfocused": "Pause streaming when tab is not focused",
+ "pause_on_unfocused": "Pause when tab is not focused",
"presets": "Presets",
"profile_background": "Profile background",
"profile_banner": "Profile banner",
@@ -470,10 +475,9 @@
"post_status_content_type": "Post status content type",
"sensitive_by_default": "Mark posts as sensitive by default",
"stop_gifs": "Pause animated images until you hover on them",
- "streaming": "Enable automatic streaming of new posts when scrolled to the top",
+ "streaming": "Automatically show new posts when scrolled to the top",
"user_mutes": "Users",
"useStreamingApi": "Receive posts and notifications real-time",
- "useStreamingApiWarning": "(Not recommended, experimental, known to skip posts)",
"text": "Text",
"theme": "Theme",
"theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
diff --git a/src/main.js b/src/main.js
index 3895da89..73bd49ed 100644
--- a/src/main.js
+++ b/src/main.js
@@ -11,6 +11,7 @@ import statusesModule from './modules/statuses.js'
import usersModule from './modules/users.js'
import apiModule from './modules/api.js'
import configModule from './modules/config.js'
+import serverSideConfigModule from './modules/serverSideConfig.js'
import shoutModule from './modules/shout.js'
import oauthModule from './modules/oauth.js'
import authFlowModule from './modules/auth_flow.js'
@@ -88,6 +89,7 @@ const persistedStateOptions = {
users: usersModule,
api: apiModule,
config: configModule,
+ serverSideConfig: serverSideConfigModule,
shout: shoutModule,
oauth: oauthModule,
authFlow: authFlowModule,
diff --git a/src/modules/config.js b/src/modules/config.js
index 1aa2878e..1bb41b7d 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -16,6 +16,7 @@ export const multiChoiceProperties = [
]
export const defaultState = {
+ expertLevel: 0, // used to track which settings to show and hide
colors: {},
theme: undefined,
customTheme: undefined,
@@ -42,7 +43,7 @@ export const defaultState = {
alwaysShowNewPostButton: false,
autohideFloatingPostButton: false,
pauseOnUnfocused: true,
- stopGifs: false,
+ stopGifs: true,
replyVisibility: 'all',
notificationVisibility: {
follows: true,
@@ -70,7 +71,7 @@ export const defaultState = {
hideFilteredStatuses: undefined, // instance default
playVideosInModal: false,
useOneClickNsfw: false,
- useContainFit: false,
+ useContainFit: true,
greentext: undefined, // instance default
useAtIcon: undefined, // instance default
mentionLinkDisplay: undefined, // instance default
diff --git a/src/modules/serverSideConfig.js b/src/modules/serverSideConfig.js
new file mode 100644
index 00000000..5c1baedb
--- /dev/null
+++ b/src/modules/serverSideConfig.js
@@ -0,0 +1,137 @@
+import { get, set } from 'lodash'
+
+const defaultApi = ({ rootState, commit }, { path, value }) => {
+ const params = {}
+ set(params, path, value)
+ return rootState
+ .api
+ .backendInteractor
+ .updateProfile({ params })
+ .then(result => {
+ commit('addNewUsers', [result])
+ commit('setCurrentUser', result)
+ })
+}
+
+const notificationsApi = ({ rootState, commit }, { path, value, oldValue }) => {
+ const settings = {}
+ set(settings, path, value)
+ return rootState
+ .api
+ .backendInteractor
+ .updateNotificationSettings({ settings })
+ .then(result => {
+ if (result.status === 'success') {
+ commit('confirmServerSideOption', { name, value })
+ } else {
+ commit('confirmServerSideOption', { name, value: oldValue })
+ }
+ })
+}
+
+/**
+ * Map that stores relation between path for reading (from user profile),
+ * for writing (into API) an what API to use.
+ *
+ * Shorthand - instead of { get, set, api? } object it's possible to use string
+ * in case default api is used and get = set
+ *
+ * If no api is specified, defaultApi is used (see above)
+ */
+export const settingsMap = {
+ 'defaultScope': 'source.privacy',
+ 'defaultNSFW': 'source.sensitive', // BROKEN: pleroma/pleroma#2837
+ 'stripRichContent': {
+ get: 'source.pleroma.no_rich_text',
+ set: 'no_rich_text'
+ },
+ // Privacy
+ 'locked': 'locked',
+ 'acceptChatMessages': {
+ get: 'pleroma.accepts_chat_messages',
+ set: 'accepts_chat_messages'
+ },
+ 'allowFollowingMove': {
+ get: 'pleroma.allow_following_move',
+ set: 'allow_following_move'
+ },
+ 'discoverable': 'source.discoverable',
+ 'hideFavorites': {
+ get: 'pleroma.hide_favorites',
+ set: 'hide_favorites'
+ },
+ 'hideFollowers': {
+ get: 'pleroma.hide_followers',
+ set: 'hide_followers'
+ },
+ 'hideFollows': {
+ get: 'pleroma.hide_follows',
+ set: 'hide_follows'
+ },
+ 'hideFollowersCount': {
+ get: 'pleroma.hide_followers_count',
+ set: 'hide_followers_count'
+ },
+ 'hideFollowsCount': {
+ get: 'pleroma.hide_follows_count',
+ set: 'hide_follows_count'
+ },
+ // NotificationSettingsAPIs
+ 'webPushHideContents': {
+ get: 'pleroma.notification_settings.hide_notification_contents',
+ set: 'hide_notification_contents',
+ api: notificationsApi
+ },
+ 'blockNotificationsFromStrangers': {
+ get: 'pleroma.notification_settings.block_from_strangers',
+ set: 'block_from_strangers',
+ api: notificationsApi
+ }
+}
+
+export const defaultState = Object.fromEntries(Object.keys(settingsMap).map(key => [key, null]))
+
+const serverSideConfig = {
+ state: { ...defaultState },
+ mutations: {
+ confirmServerSideOption (state, { name, value }) {
+ set(state, name, value)
+ },
+ wipeServerSideOption (state, { name }) {
+ set(state, name, null)
+ },
+ wipeAllServerSideOptions (state) {
+ Object.keys(settingsMap).forEach(key => {
+ set(state, key, null)
+ })
+ },
+ // Set the settings based on their path location
+ setCurrentUser (state, user) {
+ Object.entries(settingsMap).forEach((map) => {
+ const [name, value] = map
+ const { get: path = value } = value
+ set(state, name, get(user._original, path))
+ })
+ }
+ },
+ actions: {
+ setServerSideOption ({ rootState, state, commit, dispatch }, { name, value }) {
+ const oldValue = get(state, name)
+ const map = settingsMap[name]
+ if (!map) throw new Error('Invalid server-side setting')
+ const { set: path = map, api = defaultApi } = map
+ commit('wipeServerSideOption', { name })
+
+ api({ rootState, commit }, { path, value, oldValue })
+ .catch((e) => {
+ console.warn('Error setting server-side option:', e)
+ commit('confirmServerSideOption', { name, value: oldValue })
+ })
+ },
+ logout ({ commit }) {
+ commit('wipeAllServerSideOptions')
+ }
+ }
+}
+
+export default serverSideConfig
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 7025d803..f219c161 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -44,6 +44,7 @@ export const parseUser = (data) => {
const mastoShort = masto && !data.hasOwnProperty('avatar')
output.id = String(data.id)
+ output._original = data // used for server-side settings
if (masto) {
output.screen_name = data.acct