logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git
commit: bfd802ad046886230574cf2262f9c2e5f1b03a3f
parent 4d23d31fecf480abfccc4db3ac79c6640078dc3b
Author: Henry Jameson <me@hjkos.com>
Date:   Thu, 16 Mar 2023 23:18:55 +0200

setting admin settings works now. also now we have draftable settings

Diffstat:

Msrc/components/settings_modal/admin_tabs/instance_tab.vue23++++++++++++++++++++---
Msrc/components/settings_modal/helpers/boolean_setting.js15+++++++++------
Msrc/components/settings_modal/helpers/boolean_setting.vue3++-
Msrc/components/settings_modal/helpers/choice_setting.js9+++------
Asrc/components/settings_modal/helpers/draft_buttons.vue102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/components/settings_modal/helpers/integer_setting.js8++------
Msrc/components/settings_modal/helpers/integer_setting.vue4+++-
Msrc/components/settings_modal/helpers/setting.js70+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/components/settings_modal/helpers/size_setting.js5++---
Msrc/components/settings_modal/helpers/string_setting.js4----
Msrc/components/settings_modal/helpers/string_setting.vue6++++--
Msrc/modules/adminSettings.js52+++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/modules/users.js2+-
Msrc/services/api/api.service.js26++++++++++++++++++++++++--
14 files changed, 284 insertions(+), 45 deletions(-)

diff --git a/src/components/settings_modal/admin_tabs/instance_tab.vue b/src/components/settings_modal/admin_tabs/instance_tab.vue @@ -1,18 +1,35 @@ <template> - <div :label="$t('settings.general')"> + <div :label="$t('admin_dash.instance')"> <div class="setting-item"> <h2>{{ $t('admin_dash.instance') }}</h2> <ul class="setting-list"> <li> - <StringSetting source="admin" path=":pleroma.:instance.:name"> + <StringSetting + source="admin" + path=":pleroma.:instance.:name" + draft-mode + > NAME </StringSetting> </li> <li> - <StringSetting source="admin" path=":pleroma.:instance.:description"> + <StringSetting + source="admin" + path=":pleroma.:instance.:description" + draft-mode + > DESCRIPTION </StringSetting> </li> + <li> + <IntegerSetting + source="admin" + path=":pleroma.:instance.:limit" + draft-mode + > + POST LIMIT + </IntegerSetting> + </li> </ul> </div> </div> diff --git a/src/components/settings_modal/helpers/boolean_setting.js b/src/components/settings_modal/helpers/boolean_setting.js @@ -1,13 +1,16 @@ import Checkbox from 'src/components/checkbox/checkbox.vue' -import ModifiedIndicator from './modified_indicator.vue' -import ProfileSettingIndicator from './profile_setting_indicator.vue' import Setting from './setting.js' export default { + ...Setting, components: { - Checkbox, - ModifiedIndicator, - ProfileSettingIndicator + ...Setting.components, + Checkbox }, - ...Setting + methods: { + ...Setting.methods, + getValue (e) { + return e + } + } } diff --git a/src/components/settings_modal/helpers/boolean_setting.vue b/src/components/settings_modal/helpers/boolean_setting.vue @@ -4,7 +4,7 @@ class="BooleanSetting" > <Checkbox - :model-value="state" + :model-value="draftMode ? draft :state" :disabled="shouldBeDisabled" @update:modelValue="update" > @@ -20,6 +20,7 @@ :onclick="reset" /> <ProfileSettingIndicator :is-profile="isProfileSetting" /> + <DraftButtons /> </Checkbox> </label> </template> diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js @@ -1,15 +1,12 @@ import Select from 'src/components/select/select.vue' -import ModifiedIndicator from './modified_indicator.vue' -import ProfileSettingIndicator from './profile_setting_indicator.vue' import Setting from './setting.js' export default { + ...Setting, components: { - Select, - ModifiedIndicator, - ProfileSettingIndicator + ...Setting.components, + Select }, - ...Setting, props: { ...Setting.props, options: { diff --git a/src/components/settings_modal/helpers/draft_buttons.vue b/src/components/settings_modal/helpers/draft_buttons.vue @@ -0,0 +1,102 @@ +<!-- this is a helper exclusive to Setting components --> +<!-- TODO make it reusable --> +<template> + <span + class="DraftButtons" + > + <Popover + trigger="hover" + :trigger-attrs="{ 'aria-label': $t('settings.commit_value_tooltip') }" + > + <template #trigger> + &nbsp; + <button + v-if="$parent.isDirty" + class="button button-default btn" + type="button" + :title="$t('settings.commit_value')" + @click="$parent.commitDraft" + > + {{ $t('settings.commit_value') }} + </button> + </template> + <template #content> + <div class="modified-tooltip"> + {{ $t('settings.commit_value_tooltip') }} + </div> + </template> + </Popover> + <Popover + trigger="hover" + :trigger-attrs="{ 'aria-label': $t('settings.reset_value_tooltip') }" + > + <template #trigger> + &nbsp; + <button + v-if="$parent.isDirty" + class="button button-default btn" + type="button" + :title="$t('settings.reset_value')" + @click="$parent.reset" + > + {{ $t('settings.reset_value') }} + </button> + </template> + <template #content> + <div class="modified-tooltip"> + {{ $t('settings.reset_value_tooltip') }} + </div> + </template> + </Popover> + <Popover + trigger="hover" + :trigger-attrs="{ 'aria-label': $t('settings.hard_reset_value_tooltip') }" + > + <template #trigger> + &nbsp; + <button + v-if="$parent.canHardReset" + class="button button-default btn" + type="button" + :title="$t('settings.hard_reset_value')" + @click="$parent.hardReset" + > + {{ $t('settings.hard_reset_value') }} + </button> + </template> + <template #content> + <div class="modified-tooltip"> + {{ $t('settings.hard_reset_value_tooltip') }} + </div> + </template> + </Popover> + </span> +</template> + +<script> +import Popover from 'src/components/popover/popover.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faWrench } from '@fortawesome/free-solid-svg-icons' + +library.add( + faWrench +) + +export default { + components: { Popover }, + props: ['changed'] +} +</script> + +<style lang="scss"> +.DraftButtons { + display: inline-block; + position: relative; +} + +.draft-tooltip { + margin: 0.5em 1em; + min-width: 10em; + text-align: center; +} +</style> diff --git a/src/components/settings_modal/helpers/integer_setting.js b/src/components/settings_modal/helpers/integer_setting.js @@ -1,15 +1,11 @@ -import ModifiedIndicator from './modified_indicator.vue' import Setting from './setting.js' export default { - components: { - ModifiedIndicator - }, ...Setting, methods: { ...Setting.methods, - update (e) { - this.configSink(this.path, parseInt(e.target.value)) + getValue (e) { + return parseInt(e.target.value) } } } diff --git a/src/components/settings_modal/helpers/integer_setting.vue b/src/components/settings_modal/helpers/integer_setting.vue @@ -13,7 +13,7 @@ step="1" :disabled="disabled" :min="min || 0" - :value="state" + :value="draftMode ? draft :state" @change="update" > {{ ' ' }} @@ -21,6 +21,8 @@ :changed="isChanged" :onclick="reset" /> + <ProfileSettingIndicator :is-profile="isProfileSetting" /> + <DraftButtons /> </span> </template> diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js @@ -1,5 +1,16 @@ +import Checkbox from 'src/components/checkbox/checkbox.vue' +import ModifiedIndicator from './modified_indicator.vue' +import ProfileSettingIndicator from './profile_setting_indicator.vue' +import DraftButtons from './draft_buttons.vue' import { get, set } from 'lodash' + export default { + components: { + Checkbox, + ModifiedIndicator, + DraftButtons, + ProfileSettingIndicator + }, props: { path: { type: String, @@ -23,6 +34,20 @@ export default { source: { type: String, default: 'default' + }, + draftMode: { + type: Boolean, + default: false + } + }, + data () { + return { + draft: null + } + }, + created () { + if (this.draftMode) { + this.draft = this.state } }, computed: { @@ -53,7 +78,7 @@ export default { case 'profile': return (k, v) => this.$store.dispatch('setProfileOption', { name: k, value: v }) case 'admin': - return (k, v) => console.log(this.path, k, v) + return (k, v) => this.$store.dispatch('pushAdminSetting', { path: k, value: v }) default: return (k, v) => this.$store.dispatch('setOption', { name: k, value: v }) } @@ -72,25 +97,56 @@ export default { isChanged () { switch (this.source) { case 'profile': - return false case 'admin': - console.log(this.$store.state.adminSettings.modifiedPaths) - return this.$store.state.adminSettings.modifiedPaths.has(this.path) + return false default: return this.state !== this.defaultState } }, + isDirty () { + return this.draftMode && this.draft !== this.state + }, + canHardReset () { + return this.source === 'admin' && this.$store.state.adminSettings.modifiedPaths.has(this.path) + }, matchesExpertLevel () { return (this.expert || 0) <= this.$store.state.config.expertLevel > 0 } }, methods: { + getValue (e) { + return e.target.value + }, update (e) { - console.log('U', this.path, e) - this.configSink(this.path, e) + if (this.draftMode) { + this.draft = this.getValue(e) + } else { + this.configSink(this.path, this.getValue(e)) + } + }, + commitDraft () { + if (this.draftMode) { + this.configSink(this.path, this.draft) + } }, reset () { - set(this.$store.getters.mergedConfig, this.path, this.defaultState) + console.log('reset') + if (this.draftMode) { + console.log(this.draft) + console.log(this.state) + this.draft = this.state + } else { + set(this.$store.getters.mergedConfig, this.path, this.defaultState) + } + }, + hardReset () { + switch (this.source) { + case 'admin': + return this.$store.dispatch('resetAdminSetting', { path: this.path }) + .then(() => { this.draft = this.state }) + default: + console.warn('Hard reset not implemented yet!') + } } } } diff --git a/src/components/settings_modal/helpers/size_setting.js b/src/components/settings_modal/helpers/size_setting.js @@ -1,4 +1,3 @@ -import ModifiedIndicator from './modified_indicator.vue' import Select from 'src/components/select/select.vue' import Setting from './setting.js' @@ -7,11 +6,11 @@ export const defaultHorizontalUnits = ['px', 'rem', 'vw'] export const defaultVerticalUnits = ['px', 'rem', 'vh'] export default { + ...Setting, components: { - ModifiedIndicator, + ...Setting.components, Select }, - ...Setting, props: { ...Setting.props, min: Number, diff --git a/src/components/settings_modal/helpers/string_setting.js b/src/components/settings_modal/helpers/string_setting.js @@ -1,9 +1,5 @@ -import ModifiedIndicator from './modified_indicator.vue' import Setting from './setting.js' export default { - components: { - ModifiedIndicator - }, ...Setting } diff --git a/src/components/settings_modal/helpers/string_setting.vue b/src/components/settings_modal/helpers/string_setting.vue @@ -11,7 +11,7 @@ class="string-input" step="1" :disabled="disabled" - :value="state" + :value="draftMode ? draft :state" @change="update" > {{ ' ' }} @@ -19,7 +19,9 @@ :changed="isChanged" :onclick="reset" /> + <ProfileSettingIndicator :is-profile="isProfileSetting" /> + <DraftButtons /> </label> </template> -<script src="./boolean_setting.js"></script> +<script src="./string_setting.js"></script> diff --git a/src/modules/adminSettings.js b/src/modules/adminSettings.js @@ -22,8 +22,8 @@ const adminSettingsStorage = { }, actions: { setInstanceAdminSettings ({ state, commit, dispatch }, { backendDbConfig }) { - const config = {} - const modifiedPaths = new Set() + const config = state.config || {} + const modifiedPaths = state.modifiedPaths || new Set() backendDbConfig.configs.forEach(c => { const path = c.group + '.' + c.key if (c.db) { @@ -40,8 +40,54 @@ const adminSettingsStorage = { } set(config, path, convert(c.value)) }) - console.log(config) commit('updateAdminSettings', { config, modifiedPaths }) + }, + pushAdminSetting ({ rootState, state, commit, dispatch }, { path, value }) { + const [group, key, ...rest] = path.split(/\./g) + const clone = {} // not actually cloning the entire thing to avoid excessive writes + set(clone, rest.join('.'), value) + + // TODO cleanup paths in modifiedPaths + const convert = (value) => { + if (typeof value !== 'object') { + return value + } else if (Array.isArray(value)) { + return value.map(convert) + } else { + return Object.entries(value).map(([k, v]) => ({ tuple: [k, v] })) + } + } + + rootState.api.backendInteractor.pushInstanceDBConfig({ + payload: { + configs: [{ + group, + key, + value: convert(clone) + }] + } + }) + .then(() => rootState.api.backendInteractor.fetchInstanceDBConfig()) + .then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig })) + }, + resetAdminSetting ({ rootState, state, commit, dispatch }, { path }) { + console.log('ASS') + const [group, key, subkey] = path.split(/\./g) + + state.modifiedPaths.delete(path) + + return rootState.api.backendInteractor.pushInstanceDBConfig({ + payload: { + configs: [{ + group, + key, + delete: true, + subkeys: [subkey] + }] + } + }) + .then(() => rootState.api.backendInteractor.fetchInstanceDBConfig()) + .then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig })) } } } diff --git a/src/modules/users.js b/src/modules/users.js @@ -564,7 +564,7 @@ const users = { user.domainMutes = [] commit('setCurrentUser', user) commit('setServerSideStorage', user) - if (user.rights.moderator || user.rights.admin) { + if (user.rights.admin) { store.rootState.api.backendInteractor.fetchInstanceDBConfig() .then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig })) } diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js @@ -108,7 +108,7 @@ const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements' const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}` const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}` -const PLEROMA_ADMIN_CONFIG_URL = '/api/v1/pleroma/admin/config' +const PLEROMA_ADMIN_CONFIG_URL = '/api/pleroma/admin/config' const oldfetch = window.fetch @@ -1677,6 +1677,27 @@ const fetchInstanceDBConfig = ({ credentials }) => { }) } +const pushInstanceDBConfig = ({ credentials, payload }) => { + return fetch(PLEROMA_ADMIN_CONFIG_URL, { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...authHeaders(credentials) + }, + method: 'POST', + body: JSON.stringify(payload) + }) + .then((response) => { + if (response.ok) { + return response.json() + } else { + return { + error: response + } + } + }) +} + const apiService = { verifyCredentials, fetchTimeline, @@ -1791,7 +1812,8 @@ const apiService = { editAnnouncement, deleteAnnouncement, adminFetchAnnouncements, - fetchInstanceDBConfig + fetchInstanceDBConfig, + pushInstanceDBConfig } export default apiService