Merge branch 'expert-settings-and-serverside' into shigusegubu

* expert-settings-and-serverside:
  lint
  pre-emptively wipe serverside settings on logout
  fix errors in choicesetting
  fix typos in profile page
  hidden away more settings when logged out
  fix settings behaving erratically and not updating properly
  fix stripping rich content not working
  revert changes related to streaming/firehose setting, reword it so it's not confused with websocket streaming
  fix firefox rendering (??????????)
  revert to using local setting for default nsfw since backend is broken
  better phrasing
  new defaults
  expert settings toggle + server-side settings
This commit is contained in:
Henry Jameson 2022-02-28 18:26:37 +02:00
commit e6cf9efe69
24 changed files with 565 additions and 290 deletions

View file

@ -81,56 +81,56 @@
<button
v-if="type === 'flash' && flashLoaded"
class="button-unstyled attachment-button"
@click.prevent="stopFlash"
:title="$t('status.attachment_stop_flash')"
@click.prevent="stopFlash"
>
<FAIcon icon="stop" />
</button>
<button
v-if="attachment.description && size !== 'small' && !edit && type !== 'unknown'"
class="button-unstyled attachment-button"
@click.prevent="toggleDescription"
:title="$t('status.show_attachment_description')"
@click.prevent="toggleDescription"
>
<FAIcon icon="align-right" />
</button>
<button
v-if="!useModal && type !== 'unknown'"
class="button-unstyled attachment-button"
@click.prevent="openModalForce"
:title="$t('status.show_attachment_in_modal')"
@click.prevent="openModalForce"
>
<FAIcon icon="search-plus" />
</button>
<button
v-if="nsfw && hideNsfwLocal"
class="button-unstyled attachment-button"
@click.prevent="toggleHidden"
:title="$t('status.hide_attachment')"
@click.prevent="toggleHidden"
>
<FAIcon icon="times" />
</button>
<button
v-if="shiftUp"
class="button-unstyled attachment-button"
@click.prevent="onShiftUp"
:title="$t('status.move_up')"
@click.prevent="onShiftUp"
>
<FAIcon icon="chevron-left" />
</button>
<button
v-if="shiftDn"
class="button-unstyled attachment-button"
@click.prevent="onShiftDn"
:title="$t('status.move_down')"
@click.prevent="onShiftDn"
>
<FAIcon icon="chevron-right" />
</button>
<button
v-if="remove"
class="button-unstyled attachment-button"
@click.prevent="onRemove"
:title="$t('status.remove_attachment')"
@click.prevent="onRemove"
>
<FAIcon icon="trash-alt" />
</button>
@ -160,7 +160,10 @@
:href="attachment.url"
target="_blank"
>
<FAIcon size="5x" :icon="placeholderIconClass" />
<FAIcon
size="5x"
:icon="placeholderIconClass"
/>
<p>
{{ localDescription }}
</p>

View file

@ -26,8 +26,8 @@
:size="size"
:editable="editable"
:remove="removeAttachment"
:shiftUp="!(attachmentIndex === 0 && rowIndex === 0) && shiftUpAttachment"
:shiftDn="!(attachmentIndex === row.items.length - 1 && rowIndex === rows.length - 1) && shiftDnAttachment"
:shift-up="!(attachmentIndex === 0 && rowIndex === 0) && shiftUpAttachment"
:shift-dn="!(attachmentIndex === row.items.length - 1 && rowIndex === rows.length - 1) && shiftDnAttachment"
:edit="editAttachment"
:description="descriptions && descriptions[attachment.id]"
:hide-description="size === 'small' || tooManyAttachments && hidingLong"

View file

@ -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 {

View file

@ -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: {

View file

@ -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>

View file

@ -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: {

View file

@ -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>

View file

@ -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>

View file

@ -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 },

View file

@ -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 })
}
}
}
}

View file

@ -48,4 +48,11 @@
}
}
}
.settings-footer {
display: flex;
>* {
margin-right: 0.5em;
}
}
}

View file

@ -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>

View file

@ -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,11 +40,15 @@
</ul>
</li>
<li>
<BooleanSetting path="hidePostStats">
<BooleanSetting
path="hidePostStats"
expert="1"
>
{{ $t('settings.hide_post_stats') }}
</BooleanSetting>
</li>
<ChoiceSetting
v-if="user"
id="replyVisibility"
path="replyVisibility"
:options="replyVisibilityOptions"
@ -59,7 +65,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>
@ -84,7 +90,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>
@ -94,46 +103,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>

View file

@ -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
@ -47,7 +49,9 @@ const GeneralTab = {
components: {
BooleanSetting,
ChoiceSetting,
InterfaceLanguageSwitcher
InterfaceLanguageSwitcher,
ScopeSelector,
ServerSideIndicator
},
computed: {
postFormats () {
@ -67,6 +71,11 @@ const GeneralTab = {
},
instanceShoutboxPresent () { return this.$store.state.instance.shoutAvailable },
...SharedComputedObject()
},
methods: {
changeDefaultScope (value) {
this.$store.dispatch('setServerSideOption', { name: 'defaultScope', value })
}
}
}

View file

@ -45,7 +45,10 @@
</ul>
</li>
<li>
<BooleanSetting path="useStreamingApi">
<BooleanSetting
path="useStreamingApi"
expert="1"
>
{{ $t('settings.useStreamingApi') }}
<br>
<small>
@ -54,22 +57,34 @@
</BooleanSetting>
</li>
<li>
<BooleanSetting path="virtualScrolling">
<BooleanSetting
path="virtualScrolling"
expert="1"
>
{{ $t('settings.virtual_scrolling') }}
</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 v-if="instanceShoutboxPresent">
<BooleanSetting path="hideShoutbox">
<BooleanSetting
path="hideShoutbox"
expert="1"
>
{{ $t('settings.hide_shoutbox') }}
</BooleanSetting>
</li>
@ -84,13 +99,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>
@ -103,6 +133,7 @@
<li>
<BooleanSetting
path="preloadImage"
expert="1"
:disabled="!hideNsfw"
>
{{ $t('settings.preload_images') }}
@ -111,6 +142,7 @@
<li>
<BooleanSetting
path="useOneClickNsfw"
expert="1"
:disabled="!hideNsfw"
>
{{ $t('settings.use_one_click_nsfw') }}
@ -118,7 +150,10 @@
</li>
</ul>
<li>
<BooleanSetting path="loopVideo">
<BooleanSetting
path="loopVideo"
expert="1"
>
{{ $t('settings.loop_video') }}
</BooleanSetting>
<ul
@ -128,6 +163,7 @@
<li>
<BooleanSetting
path="loopVideoSilentOnly"
expert="1"
:disabled="!loopVideo || !loopSilentAvailable"
>
{{ $t('settings.loop_video_silent_only') }}
@ -142,57 +178,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>
<li>
<ChoiceSetting
id="conversationDisplay"
path="conversationDisplay"
:options="conversationDisplayOptions"
>
{{ $t('settings.conversation_display') }}
</ChoiceSetting>
</li>
<ul
v-if="conversationDisplay !== 'linear'"
class="setting-list suboptions"
>
<li>
<label for="maxDepthInThread">
{{ $t('settings.max_depth_in_thread') }}
</label>
<input
id="maxDepthInThread"
path.number="maxDepthInThread"
class="number-input"
type="number"
min="3"
step="1"
>
</li>
<li>
<ChoiceSetting
id="conversationOtherRepliesButton"
path="conversationOtherRepliesButton"
:options="conversationOtherRepliesButtonOptions"
>
{{ $t('settings.conversation_other_replies_button') }}
</ChoiceSetting>
</li>
</ul>
<h3>{{ $t('settings.mention_links') }}</h3>
<li>
<ChoiceSetting
id="mentionLinkDisplay"
@ -205,47 +198,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>
@ -254,6 +303,7 @@
id="subjectLineBehavior"
path="subjectLineBehavior"
:options="subjectLineOptions"
expert="1"
>
{{ $t('settings.subject_line_behavior') }}
</ChoiceSetting>
@ -268,43 +318,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>

View file

@ -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 () {

View file

@ -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>

View file

@ -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) => {

View file

@ -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>

View file

@ -259,13 +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",
"mentions_new_style": "Fancier mention links",
"mentions_new_place": "Put mentions on a separate line",
"mention_links": "Mention links",
"mfa": {
"otp": "OTP",
"setup_otp": "Setup OTP",
@ -402,6 +403,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 +421,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 +435,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",
@ -467,18 +470,10 @@
"subject_line_email": "Like email: \"re: subject\"",
"subject_line_mastodon": "Like mastodon: copy as is",
"subject_line_noop": "Do not copy",
"conversation_display": "Conversation display style",
"conversation_display_tree": "Tree-style",
"conversation_display_simple_tree": "Simplified tree-style",
"conversation_display_linear": "Linear-style",
"conversation_other_replies_button": "Show the \"other replies\" button",
"conversation_other_replies_button_below": "Below statuses",
"conversation_other_replies_button_inside": "Inside statuses",
"max_depth_in_thread": "Maximum number of levels in thread to display by default",
"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)",
@ -731,7 +726,6 @@
"reply_to": "Reply to",
"mentions": "Mentions",
"replies_list": "Replies:",
"replies_list_with_others": "Replies (+{numReplies} other): | Replies (+{numReplies} others):",
"mute_conversation": "Mute conversation",
"unmute_conversation": "Unmute conversation",
"status_unavailable": "Status unavailable",
@ -758,18 +752,7 @@
"attachment_stop_flash": "Stop Flash player",
"move_up": "Shift attachment left",
"move_down": "Shift attachment right",
"open_gallery": "Open gallery",
"thread_hide": "Hide this thread",
"thread_show": "Show this thread",
"thread_show_full": "Show everything under this thread ({numStatus} status in total, max depth {depth}) | Show everything under this thread ({numStatus} statuses in total, max depth {depth})",
"thread_show_full_with_icon": "{icon} {text}",
"thread_follow": "See the remaining part of this thread ({numStatus} status in total) | See the remaining part of this thread ({numStatus} statuses in total)",
"thread_follow_with_icon": "{icon} {text}",
"ancestor_follow": "See {numReplies} other reply under this status | See {numReplies} other replies under this status",
"ancestor_follow_with_icon": "{icon} {text}",
"show_all_conversation_with_icon": "{icon} {text}",
"show_all_conversation": "Show full conversation ({numStatus} other status) | Show full conversation ({numStatus} other statuses)",
"show_only_conversation_under_this": "Only show replies to this status"
"open_gallery": "Open gallery"
},
"user_card": {
"approve": "Approve",

View file

@ -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'
@ -90,6 +91,7 @@ const persistedStateOptions = {
users: usersModule,
api: apiModule,
config: configModule,
serverSideConfig: serverSideConfigModule,
shout: shoutModule,
oauth: oauthModule,
authFlow: authFlowModule,

View file

@ -18,6 +18,7 @@ export const multiChoiceProperties = [
]
export const defaultState = {
expertLevel: 0, // used to track which settings to show and hide
colors: {},
theme: undefined,
customTheme: undefined,
@ -43,7 +44,7 @@ export const defaultState = {
alwaysShowNewPostButton: false,
autohideFloatingPostButton: false,
pauseOnUnfocused: true,
stopGifs: false,
stopGifs: true,
replyVisibility: 'all',
notificationVisibility: {
follows: true,
@ -71,7 +72,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

View file

@ -0,0 +1,119 @@
import { get, set } from 'lodash'
export const settingsMapGet = {
'defaultScope': 'source.privacy',
'defaultNSFW': 'source.sensitive', // BROKEN: pleroma/pleroma#2837
'stripRichContent': 'source.pleroma.no_rich_text',
// Privacy
'locked': 'locked',
'acceptChatMessages': 'pleroma.accepts_chat_messages',
'allowFollowingMove': 'pleroma.allow_following_move',
'discoverable': 'source.discoverable',
'hideFavorites': 'pleroma.hide_favorites',
'hideFollowers': 'pleroma.hide_followers',
'hideFollows': 'pleroma.hide_follows',
'hideFollowersCount': 'pleroma.hide_followers_count',
'hideFollowsCount': 'pleroma.hide_follows_count',
// NotificationSettingsAPIs
'webPushHideContents': 'pleroma.notification_settings.hide_notification_contents',
'blockNotificationsFromStrangers': 'pleroma.notification_settings.block_from_strangers'
}
export const settingsMapSet = {
'defaultScope': 'source.privacy',
'defaultNSFW': 'source.sensitive',
'stripRichContent': 'no_rich_text',
// Privacy
'locked': 'locked',
'acceptChatMessages': 'accepts_chat_messages',
'allowFollowingMove': 'allow_following_move',
'discoverable': 'source.discoverable',
'hideFavorites': 'hide_favorites',
'hideFollowers': 'hide_followers',
'hideFollows': 'hide_follows',
'hideFollowersCount': 'hide_followers_count',
'hideFollowsCount': 'hide_follows_count',
// NotificationSettingsAPIs
'webPushHideContents': 'hide_notification_contents',
'blockNotificationsFromStrangers': 'block_from_strangers'
}
export const customAPIs = {
__defaultApi: 'updateProfile',
'webPushHideContents': 'updateNotificationSettings',
'blockNotificationsFromStrangers': 'updateNotificationSettings'
}
export const defaultState = Object.fromEntries(Object.keys(settingsMapGet).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(settingsMapGet).forEach(key => {
set(state, key, null)
})
},
// Set the settings based on their path location
setCurrentUser (state, user) {
Object.entries(settingsMapGet).forEach(([name, path]) => {
set(state, name, get(user._original, path))
})
}
},
actions: {
setServerSideOption ({ rootState, state, commit, dispatch }, { name, value }) {
const oldValue = get(state, name)
const params = {}
const path = settingsMapSet[name]
if (!path) throw new Error('Invalid server-side setting')
commit('wipeServerSideOption', { name })
const customAPIName = customAPIs[name] || customAPIs.__defaultApi
const api = rootState.api.backendInteractor[customAPIName]
let prefix = ''
switch (customAPIName) {
case 'updateNotificationSettings':
prefix = 'settings.'
break
default:
prefix = 'params.'
break
}
set(params, prefix + path, value)
api(params)
.then((result) => {
switch (customAPIName) {
case 'updateNotificationSettings':
console.log(result)
if (result.status === 'success') {
commit('confirmServerSideOption', { name, value })
} else {
commit('confirmServerSideOption', { name, value: oldValue })
}
break
default:
commit('addNewUsers', [result])
commit('setCurrentUser', result)
break
}
console.log(state)
})
.catch((e) => {
console.warn('Error setting server-side option:', e)
commit('confirmServerSideOption', { name, value: oldValue })
})
},
logout ({ commit }) {
commit('wipeAllServerSideOptions')
}
}
}
export default serverSideConfig

View file

@ -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