pleroma-fe/src/components/settings_modal/helpers/setting.js

420 lines
11 KiB
JavaScript
Raw Normal View History

2026-01-06 16:23:17 +02:00
import { cloneDeep, get, isEqual, set } from 'lodash'
2026-01-08 17:26:52 +02:00
2026-01-06 16:23:17 +02:00
import DraftButtons from './draft_buttons.vue'
import ModifiedIndicator from './modified_indicator.vue'
import ProfileSettingIndicator from './profile_setting_indicator.vue'
2026-02-13 14:26:39 +02:00
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
2026-02-27 15:49:44 +02:00
import { useLocalConfigStore } from 'src/stores/local_config.js'
2026-02-13 14:26:39 +02:00
export default {
components: {
ModifiedIndicator,
DraftButtons,
2026-01-06 16:22:52 +02:00
ProfileSettingIndicator,
},
props: {
2024-09-24 03:07:27 +03:00
modelValue: {
type: String,
2026-01-06 16:22:52 +02:00
default: null,
2024-09-24 03:07:27 +03:00
},
description: {
type: String,
default: null,
},
path: {
type: [String, Array],
2026-01-06 16:22:52 +02:00
required: false,
},
2025-12-10 19:57:34 +02:00
showDescription: {
type: Boolean,
2026-01-06 16:22:52 +02:00
required: false,
2025-12-10 19:57:34 +02:00
},
2025-12-08 17:09:07 +02:00
descriptionPathOverride: {
type: [String, Array],
2026-01-06 16:22:52 +02:00
required: false,
2025-12-08 17:09:07 +02:00
},
2025-12-03 23:05:46 +02:00
suggestions: {
type: [String, Array],
2026-01-06 16:22:52 +02:00
required: false,
2025-12-03 23:05:46 +02:00
},
subgroup: {
type: String,
2026-01-06 16:22:52 +02:00
required: false,
},
disabled: {
type: Boolean,
2026-01-06 16:22:52 +02:00
default: false,
},
2026-02-24 21:16:38 +02:00
local: {
type: Boolean,
default: false,
},
parentPath: {
2026-01-06 16:22:52 +02:00
type: [String, Array],
},
parentInvert: {
type: Boolean,
2026-01-06 16:22:52 +02:00
default: false,
},
expert: {
type: [Number, String],
2026-01-06 16:22:52 +02:00
default: 0,
},
source: {
type: String,
2026-01-06 16:22:52 +02:00
default: undefined,
},
2026-01-06 16:22:52 +02:00
hideDraftButtons: {
// this is for the weird backend hybrid (Boolean|String or Boolean|Number) settings
2025-12-07 23:11:54 +02:00
required: false,
2026-01-06 16:22:52 +02:00
type: Boolean,
2025-12-03 12:19:20 +02:00
},
hideLabel: {
2026-01-06 16:22:52 +02:00
type: Boolean,
2025-12-03 12:19:20 +02:00
},
hideDescription: {
2026-01-06 16:22:52 +02:00
type: Boolean,
},
swapDescriptionAndLabel: {
2026-01-06 16:22:52 +02:00
type: Boolean,
},
2025-12-03 23:05:46 +02:00
backendDescriptionPath: {
2026-01-06 16:22:52 +02:00
type: [String, Array],
2025-12-03 23:05:46 +02:00
},
overrideBackendDescription: {
2026-01-06 16:22:52 +02:00
type: Boolean,
},
overrideBackendDescriptionLabel: {
2026-01-06 16:22:52 +02:00
type: [Boolean, String],
},
draftMode: {
type: Boolean,
2026-01-06 16:22:52 +02:00
default: undefined,
},
timedApplyMode: {
type: Boolean,
2026-01-06 16:22:52 +02:00
default: false,
},
2023-03-21 22:46:40 +02:00
},
inject: {
defaultSource: {
2026-01-06 16:22:52 +02:00
default: 'default',
2023-03-21 22:46:40 +02:00
},
defaultDraftMode: {
2026-01-06 16:22:52 +02:00
default: false,
},
},
2026-01-06 16:22:52 +02:00
data() {
return {
2026-01-06 16:22:52 +02:00
localDraft: null,
}
},
2026-01-06 16:22:52 +02:00
created() {
if (
this.realDraftMode &&
(this.realSource !== 'admin' || this.path == null)
) {
2025-12-01 20:09:05 +02:00
this.draft = cloneDeep(this.state)
}
},
computed: {
draft: {
2026-01-06 16:22:52 +02:00
get() {
2024-09-24 03:07:27 +03:00
if (this.realSource === 'admin' || this.path == null) {
return get(this.$store.state.adminSettings.draft, this.canonPath)
} else {
return this.localDraft
}
},
2026-01-06 16:22:52 +02:00
set(value) {
2024-09-24 03:07:27 +03:00
if (this.realSource === 'admin' || this.path == null) {
2026-01-06 16:22:52 +02:00
this.$store.commit('updateAdminDraft', {
path: this.canonPath,
value,
})
} else {
this.localDraft = value
}
2026-01-06 16:22:52 +02:00
},
},
2026-01-06 16:22:52 +02:00
state() {
2024-09-24 03:07:27 +03:00
if (this.path == null) {
return this.modelValue
}
const value = get(this.configSource, this.canonPath)
if (value === undefined) {
return this.defaultState
} else {
return value
}
},
2026-01-06 16:22:52 +02:00
visibleState() {
return this.realDraftMode ? this.draft : this.state
},
2026-01-06 16:22:52 +02:00
realSource() {
2023-03-21 22:46:40 +02:00
return this.source || this.defaultSource
},
2026-01-06 16:22:52 +02:00
realDraftMode() {
return typeof this.draftMode === 'undefined'
? this.defaultDraftMode
: this.draftMode
2023-03-21 22:46:40 +02:00
},
2026-01-06 16:22:52 +02:00
backendDescription() {
return get(
this.$store.state.adminSettings.descriptions,
this.descriptionPath,
)
2023-03-19 21:27:07 +02:00
},
2026-01-06 16:22:52 +02:00
backendDescriptionLabel() {
if (this.realSource !== 'admin') return ''
2026-01-06 16:22:52 +02:00
if (
this.overrideBackendDescriptionLabel !== '' &&
typeof this.overrideBackendDescriptionLabel === 'string'
) {
2025-12-08 22:29:47 +02:00
return this.overrideBackendDescriptionLabel
}
if (!this.backendDescription || this.overrideBackendDescriptionLabel) {
2026-01-06 16:22:52 +02:00
return this.$t(
[
'admin_dash',
'temp_overrides',
...this.canonPath.map((p) => p.replace(/\./g, '_DOT_')),
'label',
].join('.'),
)
} else {
return this.swapDescriptionAndLabel
? this.backendDescription?.description
: this.backendDescription?.label
}
2023-03-19 21:27:07 +02:00
},
2026-01-06 16:22:52 +02:00
backendDescriptionDescription() {
2025-12-10 19:57:34 +02:00
if (this.description) return this.description
if (this.realSource !== 'admin') return ''
if (this.hideDescription) return null
if (!this.backendDescription || this.overrideBackendDescription) {
2026-01-06 16:22:52 +02:00
return this.$t(
[
'admin_dash',
'temp_overrides',
...this.canonPath.map((p) => p.replace(/\./g, '_DOT_')),
'description',
].join('.'),
)
} else {
return this.swapDescriptionAndLabel
? this.backendDescription?.label
: this.backendDescription?.description
}
2023-03-19 21:27:07 +02:00
},
2026-01-06 16:22:52 +02:00
backendDescriptionSuggestions() {
2025-12-03 23:05:46 +02:00
return this.backendDescription?.suggestions || this.suggestions
},
2026-01-06 16:22:52 +02:00
shouldBeDisabled() {
2024-09-24 03:07:27 +03:00
if (this.path == null) {
return this.disabled
}
2025-12-01 20:09:05 +02:00
let parentValue = null
if (this.parentPath !== undefined && this.realSource === 'admin') {
if (this.realDraftMode) {
2026-01-06 16:22:52 +02:00
parentValue = get(
this.$store.state.adminSettings.draft,
this.parentPath,
)
2025-12-01 20:09:05 +02:00
} else {
parentValue = get(this.configSource, this.parentPath)
}
}
2026-01-06 16:22:52 +02:00
return (
this.disabled ||
(parentValue !== null
? this.parentInvert
? parentValue
: !parentValue
: false)
)
},
configSource() {
2023-03-21 22:46:40 +02:00
switch (this.realSource) {
case 'profile':
return this.$store.state.profileConfig
2023-03-14 21:50:43 +02:00
case 'admin':
return this.$store.state.adminSettings.config
default:
2026-02-13 14:26:39 +02:00
return useSyncConfigStore().mergedConfig
}
},
2026-01-06 16:22:52 +02:00
configSink() {
2024-09-24 03:07:27 +03:00
if (this.path == null) {
return (k, v) => this.$emit('update:modelValue', v)
2024-09-24 03:07:27 +03:00
}
2026-02-13 14:26:39 +02:00
2023-03-21 22:46:40 +02:00
switch (this.realSource) {
case 'profile':
2026-01-06 16:22:52 +02:00
return (k, v) =>
this.$store.dispatch('setProfileOption', { name: k, value: v })
2023-03-14 21:50:43 +02:00
case 'admin':
2026-01-06 16:22:52 +02:00
return (k, v) =>
this.$store.dispatch('pushAdminSetting', { path: k, value: v })
default:
2026-02-13 14:26:39 +02:00
return (readPath, value) => {
2026-02-27 14:46:01 +02:00
const writePath = `${readPath}`
2026-02-13 14:26:39 +02:00
if (!this.timedApplyMode) {
2026-02-24 21:16:38 +02:00
if (this.local) {
useLocalConfigStore().set({
path: writePath,
value,
})
} else {
useSyncConfigStore().setSimplePrefAndSave({
path: writePath,
value,
})
}
2026-02-13 14:26:39 +02:00
} else {
if (useInterfaceStore().temporaryChangesTimeoutId !== null) {
console.error("Can't track more than one temporary change")
return
}
const oldValue = get(this.configSource, readPath)
2026-02-24 21:16:38 +02:00
if (this.local) {
useLocalConfigStore().setTemporarily({ path: writePath, value })
} else {
useSyncConfigStore().setPreference({ path: writePath, value })
}
2026-02-13 14:26:39 +02:00
const confirm = () => {
2026-02-24 21:16:38 +02:00
if (this.local) {
useLocalConfigStore().set({ path: writePath, value })
} else {
useSyncConfigStore().pushSyncConfig()
}
2026-02-13 14:26:39 +02:00
useInterfaceStore().clearTemporaryChanges()
}
const revert = () => {
2026-02-24 21:16:38 +02:00
if (this.local) {
useLocalConfigStore().unsetTemporarily({ path: writePath, value })
} else {
useSyncConfigStore().setPreference({
path: writePath,
value: oldValue,
})
}
2026-02-13 14:26:39 +02:00
useInterfaceStore().clearTemporaryChanges()
}
useInterfaceStore().setTemporaryChanges({ confirm, revert })
}
}
}
},
2026-01-06 16:22:52 +02:00
defaultState() {
2023-03-21 22:46:40 +02:00
switch (this.realSource) {
case 'profile':
return {}
default:
2026-02-13 14:26:39 +02:00
return get(useInstanceStore().prefsStorage, this.path)
}
},
2026-01-06 16:22:52 +02:00
isProfileSetting() {
2023-03-21 22:46:40 +02:00
return this.realSource === 'profile'
},
2026-01-06 16:22:52 +02:00
isChanged() {
2024-09-24 03:07:27 +03:00
if (this.path == null) return false
2023-03-21 22:46:40 +02:00
switch (this.realSource) {
2023-03-14 21:50:43 +02:00
case 'profile':
case 'admin':
return false
2023-03-14 21:50:43 +02:00
default:
return this.state !== this.defaultState
}
},
2026-01-06 16:22:52 +02:00
canonPath() {
2024-09-24 03:07:27 +03:00
if (this.path == null) return null
return Array.isArray(this.path) ? this.path : this.path.split('.')
},
2026-01-06 16:22:52 +02:00
descriptionPath() {
if (this.path == null) return null
2025-12-08 17:09:07 +02:00
if (this.descriptionPathOverride) return this.descriptionPathOverride
const path = Array.isArray(this.path) ? this.path : this.path.split('.')
if (this.subgroup) {
return [
2026-01-06 16:22:52 +02:00
...path.slice(0, path.length - 1),
':subgroup,' + this.subgroup,
...path.slice(path.length - 1),
]
}
return path
},
2026-01-06 16:22:52 +02:00
isDirty() {
2024-09-24 03:07:27 +03:00
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 && !isEqual(this.draft, this.state)
}
},
2026-01-06 16:22:52 +02:00
canHardReset() {
return (
this.realSource === 'admin' &&
this.$store.state.adminSettings.modifiedPaths?.has(
this.canonPath.join(' -> '),
)
)
},
2026-01-06 16:22:52 +02:00
matchesExpertLevel() {
2025-12-19 19:27:33 +02:00
const settingExpertLevel = this.expert || 0
2026-02-13 14:26:39 +02:00
const userToggleExpert =
useSyncConfigStore().mergedConfig.expertLevel || 0
2025-12-19 19:27:33 +02:00
return settingExpertLevel <= userToggleExpert
2026-01-06 16:22:52 +02:00
},
},
methods: {
2026-01-06 16:22:52 +02:00
getValue(e) {
return e.target.value
},
2026-01-06 16:22:52 +02:00
update(e) {
2023-03-21 22:46:40 +02:00
if (this.realDraftMode) {
this.draft = this.getValue(e)
} else {
this.configSink(this.path, this.getValue(e))
}
},
2026-01-06 16:22:52 +02:00
commitDraft() {
2023-03-21 22:46:40 +02:00
if (this.realDraftMode) {
this.configSink(this.path, this.draft)
}
},
2026-01-06 16:22:52 +02:00
reset() {
2023-03-21 22:46:40 +02:00
if (this.realDraftMode) {
2023-05-24 11:44:41 +03:00
this.draft = cloneDeep(this.state)
} else {
2026-01-06 16:22:52 +02:00
set(
2026-02-13 14:26:39 +02:00
useSyncConfigStore().mergedConfig,
2026-01-06 16:22:52 +02:00
this.path,
cloneDeep(this.defaultState),
)
}
},
2026-01-06 16:22:52 +02:00
hardReset() {
2023-03-21 22:46:40 +02:00
switch (this.realSource) {
case 'admin':
2026-01-06 16:22:52 +02:00
return this.$store
.dispatch('resetAdminSetting', { path: this.path })
.then(() => {
this.draft = this.state
})
default:
console.warn('Hard reset not implemented yet!')
}
2026-01-06 16:22:52 +02:00
},
},
}