From 4d23d31fecf480abfccc4db3ac79c6640078dc3b Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 14 Mar 2023 21:50:43 +0200
Subject: initial admin settings prototype (WIP)

---
 .../settings_modal/settings_modal_admin_content.vue | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 src/components/settings_modal/settings_modal_admin_content.vue

(limited to 'src/components/settings_modal/settings_modal_admin_content.vue')

diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue
new file mode 100644
index 00000000..9873b127
--- /dev/null
+++ b/src/components/settings_modal/settings_modal_admin_content.vue
@@ -0,0 +1,21 @@
+<template>
+  <tab-switcher
+    ref="tabSwitcher"
+    class="settings_tab-switcher"
+    :side-tab-bar="true"
+    :scrollable-tabs="true"
+    :body-scroll-lock="bodyLock"
+  >
+    <div
+      :label="$t('settings.general')"
+      icon="wrench"
+      data-tab-name="general"
+    >
+      <InstanceTab />
+    </div>
+  </tab-switcher>
+</template>
+
+<script src="./settings_modal_admin_content.js"></script>
+
+<style src="./settings_modal_admin_content.scss" lang="scss"></style>
-- 
cgit v1.2.3-70-g09d2


From 332ad77e3579d2b512ba236b3f2c94ad8875864d Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 19 Mar 2023 21:27:07 +0200
Subject: limits tab, backend descriptions

---
 .../settings_modal/admin_tabs/instance_tab.vue     | 103 +++++++++++---
 .../settings_modal/admin_tabs/limits_tab.js        |  29 ++++
 .../settings_modal/admin_tabs/limits_tab.vue       | 152 +++++++++++++++++++++
 .../settings_modal/helpers/boolean_setting.vue     |  13 +-
 .../settings_modal/helpers/integer_setting.vue     |  13 +-
 src/components/settings_modal/helpers/setting.js   |  10 ++
 .../settings_modal/helpers/string_setting.vue      |  13 +-
 src/components/settings_modal/settings_modal.scss  |   6 +
 .../settings_modal/settings_modal_admin_content.js |   4 +-
 .../settings_modal_admin_content.vue               |   9 +-
 src/modules/adminSettings.js                       |  24 +++-
 src/modules/users.js                               |   2 +
 src/services/api/api.service.js                    |  17 +++
 13 files changed, 370 insertions(+), 25 deletions(-)
 create mode 100644 src/components/settings_modal/admin_tabs/limits_tab.js
 create mode 100644 src/components/settings_modal/admin_tabs/limits_tab.vue

(limited to 'src/components/settings_modal/settings_modal_admin_content.vue')

diff --git a/src/components/settings_modal/admin_tabs/instance_tab.vue b/src/components/settings_modal/admin_tabs/instance_tab.vue
index 18ba6127..ad271293 100644
--- a/src/components/settings_modal/admin_tabs/instance_tab.vue
+++ b/src/components/settings_modal/admin_tabs/instance_tab.vue
@@ -12,6 +12,15 @@
             NAME
           </StringSetting>
         </li>
+        <li>
+          <StringSetting
+            source="admin"
+            path=":pleroma.:instance.:email"
+            draft-mode
+          >
+            ADMIN EMAIL
+          </StringSetting>
+        </li>
         <li>
           <StringSetting
             source="admin"
@@ -22,13 +31,85 @@
           </StringSetting>
         </li>
         <li>
-          <IntegerSetting
+          <StringSetting
             source="admin"
-            path=":pleroma.:instance.:limit"
+            path=":pleroma.:instance.:short_description"
             draft-mode
           >
-            POST LIMIT
-          </IntegerSetting>
+            SHORT DESCRIPTION
+          </StringSetting>
+        </li>
+        <li>
+          <StringSetting
+            source="admin"
+            path=":pleroma.:instance.:instance_thumbnail"
+            draft-mode
+          >
+            INSTANCE THUMBNAIL
+          </StringSetting>
+        </li>
+        <li>
+          <StringSetting
+            source="admin"
+            path=":pleroma.:instance.:background_image"
+            draft-mode
+          >
+            BACKGROUND IMAGE
+          </StringSetting>
+        </li>
+        <li>
+          <BooleanSetting
+            source="admin"
+            path=":pleroma.:instance.:public"
+            draft-mode
+          >
+            PUBLIC
+          </BooleanSetting>
+        </li>
+      </ul>
+    </div>
+    <div class="setting-item">
+      <h2>{{ $t('admin_dash.registrations') }}</h2>
+      <ul class="setting-list">
+        <li>
+          <BooleanSetting
+            source="admin"
+            path=":pleroma.:instance.:registrations_open"
+            draft-mode
+          >
+            REGISTRATIONS OPEN
+          </BooleanSetting>
+          <ul class="setting-list suboptions">
+            <li>
+              <BooleanSetting
+                source="admin"
+                path=":pleroma.:instance.:invites_enabled"
+                parent-path=":pleroma.:instance.:registrations_open"
+                :parent-invert="true"
+                draft-mode
+              >
+                INVITES ENABLED
+              </BooleanSetting>
+            </li>
+          </ul>
+        </li>
+        <li>
+          <BooleanSetting
+            source="admin"
+            path=":pleroma.:instance.:account_activation_required"
+            draft-mode
+          >
+            ACTIVATION REQUIRED
+          </BooleanSetting>
+        </li>
+        <li>
+          <BooleanSetting
+            source="admin"
+            path=":pleroma.:instance.:account_approval_required"
+            draft-mode
+          >
+            APPROVAL REQUIRED
+          </BooleanSetting>
         </li>
       </ul>
     </div>
@@ -36,17 +117,3 @@
 </template>
 
 <script src="./instance_tab.js"></script>
-
-<style lang="scss">
-.column-settings {
-  display: flex;
-  justify-content: space-evenly;
-  flex-wrap: wrap;
-}
-
-.column-settings .size-label {
-  display: block;
-  margin-bottom: 0.5em;
-  margin-top: 0.5em;
-}
-</style>
diff --git a/src/components/settings_modal/admin_tabs/limits_tab.js b/src/components/settings_modal/admin_tabs/limits_tab.js
new file mode 100644
index 00000000..684739c3
--- /dev/null
+++ b/src/components/settings_modal/admin_tabs/limits_tab.js
@@ -0,0 +1,29 @@
+import BooleanSetting from '../helpers/boolean_setting.vue'
+import ChoiceSetting from '../helpers/choice_setting.vue'
+import IntegerSetting from '../helpers/integer_setting.vue'
+import StringSetting from '../helpers/string_setting.vue'
+
+import SharedComputedObject from '../helpers/shared_computed_object.js'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faGlobe
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faGlobe
+)
+
+const LimitsTab = {
+  data () {},
+  components: {
+    BooleanSetting,
+    ChoiceSetting,
+    IntegerSetting,
+    StringSetting
+  },
+  computed: {
+    ...SharedComputedObject()
+  }
+}
+
+export default LimitsTab
diff --git a/src/components/settings_modal/admin_tabs/limits_tab.vue b/src/components/settings_modal/admin_tabs/limits_tab.vue
new file mode 100644
index 00000000..3f07c554
--- /dev/null
+++ b/src/components/settings_modal/admin_tabs/limits_tab.vue
@@ -0,0 +1,152 @@
+<template>
+  <div :label="$t('admin_dash.instance')">
+    <div class="setting-item">
+      <h2>{{ $t('admin_dash.arbitrary_limits') }}</h2>
+      <ul class="setting-list">
+        <li>
+          <h3>{{ $t('admin_dash.limits.posts') }}</h3>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:limit"
+            draft-mode
+          >
+            POST LIMIT
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:remote_limit"
+            draft-mode
+          >
+            POST LIMIT (remote)
+          </IntegerSetting>
+        </li>
+        <li>
+          <h3>{{ $t('admin_dash.limits.uploads') }}</h3>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:description_limit"
+            draft-mode
+          >
+            IMAGE DESCRIPTION LIMIT
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:upload_limit"
+            draft-mode
+          >
+            UPLOAD LIMIT KiB
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:max_media_attachments"
+            draft-mode
+          >
+            MAX ATTACHMENTS
+          </IntegerSetting>
+        </li>
+        <li>
+          <h3>{{ $t('admin_dash.limits.users') }}</h3>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:user_bio_length"
+            draft-mode
+          >
+            BIO LENGTH
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:user_name_length"
+            draft-mode
+          >
+            NAME LENGTH
+          </IntegerSetting>
+        </li>
+        <li>
+          <h4>{{ $t('admin_dash.limits.profile_fields') }}</h4>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:max_account_fields"
+            draft-mode
+          >
+            MAX ACCOUNT FIELDS
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:max_remote_account_fields"
+            draft-mode
+          >
+            MAX ACCOUNT FIELDS (remote)
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:account_field_name_length"
+            draft-mode
+          >
+            MAX ACCOUNT FIELD NAME
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:account_field_value_length"
+            draft-mode
+          >
+            MAX ACCOUNT VALUE NAME
+          </IntegerSetting>
+        </li>
+        <li>
+          <h4>{{ $t('admin_dash.limits.user_uploads') }}</h4>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:avatar_upload_limit"
+            draft-mode
+          >
+            MAX AVATAR SIZE KiB
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:banner_upload_limit"
+            draft-mode
+          >
+            MAX BANNER SIZE KiB
+          </IntegerSetting>
+        </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:max_pinned_statuses"
+            draft-mode
+          >
+            MAX PINNED POSTS
+          </IntegerSetting>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script src="./limits_tab.js"></script>
diff --git a/src/components/settings_modal/helpers/boolean_setting.vue b/src/components/settings_modal/helpers/boolean_setting.vue
index 7e05fe85..aedbf23e 100644
--- a/src/components/settings_modal/helpers/boolean_setting.vue
+++ b/src/components/settings_modal/helpers/boolean_setting.vue
@@ -12,7 +12,12 @@
         v-if="!!$slots.default"
         class="label"
       >
-        <slot />
+        <template v-if="backendDescription">
+          {{ backendDescriptionLabel + ' ' }}
+        </template>
+        <template v-else>
+          <slot />
+        </template>
       </span>
       {{ ' ' }}
       <ModifiedIndicator
@@ -21,6 +26,12 @@
       />
       <ProfileSettingIndicator :is-profile="isProfileSetting" />
       <DraftButtons />
+      <p
+        v-if="backendDescriptionDescription"
+        class="setting-description"
+      >
+        {{ backendDescriptionDescription + ' ' }}
+      </p>
     </Checkbox>
   </label>
 </template>
diff --git a/src/components/settings_modal/helpers/integer_setting.vue b/src/components/settings_modal/helpers/integer_setting.vue
index e900b87c..e935dfb0 100644
--- a/src/components/settings_modal/helpers/integer_setting.vue
+++ b/src/components/settings_modal/helpers/integer_setting.vue
@@ -4,7 +4,12 @@
     class="IntegerSetting"
   >
     <label :for="path">
-      <slot />
+      <template v-if="backendDescription">
+        {{ backendDescriptionLabel + ' ' }}
+      </template>
+      <template v-else>
+        <slot />
+      </template>
     </label>
     <input
       :id="path"
@@ -23,6 +28,12 @@
     />
     <ProfileSettingIndicator :is-profile="isProfileSetting" />
     <DraftButtons />
+    <p
+      v-if="backendDescriptionDescription"
+      class="setting-description"
+    >
+      {{ backendDescriptionDescription + ' ' }}
+    </p>
   </span>
 </template>
 
diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js
index 0971b919..f270216f 100644
--- a/src/components/settings_modal/helpers/setting.js
+++ b/src/components/settings_modal/helpers/setting.js
@@ -59,6 +59,16 @@ export default {
         return value
       }
     },
+    backendDescription () {
+      console.log(get(this.$store.state.adminSettings.descriptions, this.path))
+      return get(this.$store.state.adminSettings.descriptions, this.path)
+    },
+    backendDescriptionLabel () {
+      return this.backendDescription.label
+    },
+    backendDescriptionDescription () {
+      return this.backendDescription.description
+    },
     shouldBeDisabled () {
       const parentValue = this.parentPath !== undefined ? get(this.configSource, this.parentPath) : null
       return this.disabled || (parentValue !== null ? (this.parentInvert ? parentValue : !parentValue) : false)
diff --git a/src/components/settings_modal/helpers/string_setting.vue b/src/components/settings_modal/helpers/string_setting.vue
index 0a71aeab..91a4afa4 100644
--- a/src/components/settings_modal/helpers/string_setting.vue
+++ b/src/components/settings_modal/helpers/string_setting.vue
@@ -4,7 +4,12 @@
     class="StringSetting"
   >
     <label :for="path">
-      <slot />
+      <template v-if="backendDescription">
+        {{ backendDescriptionLabel + ' ' }}
+      </template>
+      <template v-else>
+        <slot />
+      </template>
     </label>
     <input
       :id="path"
@@ -21,6 +26,12 @@
     />
     <ProfileSettingIndicator :is-profile="isProfileSetting" />
     <DraftButtons />
+    <p
+      v-if="backendDescriptionDescription"
+      class="setting-description"
+    >
+      {{ backendDescriptionDescription + ' ' }}
+    </p>
   </label>
 </template>
 
diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss
index f5861229..4cce6099 100644
--- a/src/components/settings_modal/settings_modal.scss
+++ b/src/components/settings_modal/settings_modal.scss
@@ -17,6 +17,12 @@
     }
   }
 
+  .setting-description {
+    margin-top: 0.2em;
+    margin-bottom: 2em;
+    font-size: 70%;
+  }
+
   .settings-modal-panel {
     overflow: hidden;
     transition: transform;
diff --git a/src/components/settings_modal/settings_modal_admin_content.js b/src/components/settings_modal/settings_modal_admin_content.js
index 88ba1755..c6c8837f 100644
--- a/src/components/settings_modal/settings_modal_admin_content.js
+++ b/src/components/settings_modal/settings_modal_admin_content.js
@@ -3,6 +3,7 @@ import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
 import DataImportExportTab from './tabs/data_import_export_tab.vue'
 import MutesAndBlocksTab from './tabs/mutes_and_blocks_tab.vue'
 import InstanceTab from './admin_tabs/instance_tab.vue'
+import LimitsTab from './admin_tabs/limits_tab.vue'
 
 import { library } from '@fortawesome/fontawesome-svg-core'
 import {
@@ -33,7 +34,8 @@ const SettingsModalAdminContent = {
 
     DataImportExportTab,
     MutesAndBlocksTab,
-    InstanceTab
+    InstanceTab,
+    LimitsTab
   },
   computed: {
     isLoggedIn () {
diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue
index 9873b127..16b55828 100644
--- a/src/components/settings_modal/settings_modal_admin_content.vue
+++ b/src/components/settings_modal/settings_modal_admin_content.vue
@@ -7,12 +7,19 @@
     :body-scroll-lock="bodyLock"
   >
     <div
-      :label="$t('settings.general')"
+      :label="$t('admin_dash.instance')"
       icon="wrench"
       data-tab-name="general"
     >
       <InstanceTab />
     </div>
+    <div
+      :label="$t('admin_dash.limits')"
+      icon="wrench"
+      data-tab-name="limits"
+    >
+      <LimitsTab />
+    </div>
   </tab-switcher>
 </template>
 
diff --git a/src/modules/adminSettings.js b/src/modules/adminSettings.js
index d1df67d4..44a4d409 100644
--- a/src/modules/adminSettings.js
+++ b/src/modules/adminSettings.js
@@ -3,7 +3,8 @@ import { set, cloneDeep } from 'lodash'
 export const defaultState = {
   needsReboot: null,
   config: null,
-  modifiedPaths: null
+  modifiedPaths: null,
+  descriptions: null
 }
 
 export const newUserFlags = {
@@ -18,6 +19,9 @@ const adminSettingsStorage = {
     updateAdminSettings (state, { config, modifiedPaths }) {
       state.config = config
       state.modifiedPaths = modifiedPaths
+    },
+    updateAdminDescriptions (state, { descriptions }) {
+      state.descriptions = descriptions
     }
   },
   actions: {
@@ -40,8 +44,25 @@ const adminSettingsStorage = {
         }
         set(config, path, convert(c.value))
       })
+      console.log(config[':pleroma'][':welcome'])
       commit('updateAdminSettings', { config, modifiedPaths })
     },
+    setInstanceAdminDescriptions ({ state, commit, dispatch }, { backendDescriptions }) {
+      const convert = ({ children, description, label, key = '<ROOT>', group, suggestions }, path, acc) => {
+        const newPath = group ? group + '.' + key : key
+        const obj = { description, label, suggestions }
+        if (Array.isArray(children)) {
+          children.forEach(c => {
+            convert(c, '.' + newPath, obj)
+          })
+        }
+        set(acc, newPath, obj)
+      }
+
+      const descriptions = {}
+      backendDescriptions.forEach(d => convert(d, '', descriptions))
+      commit('updateAdminDescriptions', { descriptions })
+    },
     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
@@ -71,7 +92,6 @@ const adminSettingsStorage = {
         .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)
diff --git a/src/modules/users.js b/src/modules/users.js
index 12e582f4..45cba334 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -567,6 +567,8 @@ const users = {
               if (user.rights.admin) {
                 store.rootState.api.backendInteractor.fetchInstanceDBConfig()
                   .then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig }))
+                store.rootState.api.backendInteractor.fetchInstanceConfigDescriptions()
+                  .then(backendDescriptions => dispatch('setInstanceAdminDescriptions', { backendDescriptions }))
               }
               commit('addNewUsers', [user])
 
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 71ba1dec..073f40a3 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -109,6 +109,7 @@ const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements
 const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
 
 const PLEROMA_ADMIN_CONFIG_URL = '/api/pleroma/admin/config'
+const PLEROMA_ADMIN_DESCRIPTIONS_URL = '/api/pleroma/admin/config/descriptions'
 
 const oldfetch = window.fetch
 
@@ -1677,6 +1678,21 @@ const fetchInstanceDBConfig = ({ credentials }) => {
     })
 }
 
+const fetchInstanceConfigDescriptions = ({ credentials }) => {
+  return fetch(PLEROMA_ADMIN_DESCRIPTIONS_URL, {
+    headers: authHeaders(credentials)
+  })
+    .then((response) => {
+      if (response.ok) {
+        return response.json()
+      } else {
+        return {
+          error: response
+        }
+      }
+    })
+}
+
 const pushInstanceDBConfig = ({ credentials, payload }) => {
   return fetch(PLEROMA_ADMIN_CONFIG_URL, {
     headers: {
@@ -1813,6 +1829,7 @@ const apiService = {
   deleteAnnouncement,
   adminFetchAnnouncements,
   fetchInstanceDBConfig,
+  fetchInstanceConfigDescriptions,
   pushInstanceDBConfig
 }
 
-- 
cgit v1.2.3-70-g09d2


From 9a97e0d196c879e41dcb8bda8bd8128a039bacdc Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 21 Mar 2023 10:26:25 +0200
Subject: modal update, initial localization

---
 .../settings_modal/admin_tabs/instance_tab.vue     | 10 ++++----
 .../settings_modal/admin_tabs/limits_tab.vue       | 24 ++++++++++---------
 src/components/settings_modal/settings_modal.vue   | 15 +++++++++++-
 .../settings_modal/settings_modal_admin_content.js |  4 ++--
 .../settings_modal_admin_content.vue               |  6 ++---
 src/i18n/en.json                                   | 27 ++++++++++++++++++++++
 6 files changed, 64 insertions(+), 22 deletions(-)

(limited to 'src/components/settings_modal/settings_modal_admin_content.vue')

diff --git a/src/components/settings_modal/admin_tabs/instance_tab.vue b/src/components/settings_modal/admin_tabs/instance_tab.vue
index ff784287..411982cc 100644
--- a/src/components/settings_modal/admin_tabs/instance_tab.vue
+++ b/src/components/settings_modal/admin_tabs/instance_tab.vue
@@ -1,7 +1,7 @@
 <template>
-  <div :label="$t('admin_dash.instance')">
+  <div :label="$t('admin_dash.tabs.instance')">
     <div class="setting-item">
-      <h2>{{ $t('admin_dash.instance') }}</h2>
+      <h2>{{ $t('admin_dash.instance.instance') }}</h2>
       <ul class="setting-list">
         <li>
           <StringSetting
@@ -69,7 +69,7 @@
       </ul>
     </div>
     <div class="setting-item">
-      <h2>{{ $t('admin_dash.registrations') }}</h2>
+      <h2>{{ $t('admin_dash.instance.registrations') }}</h2>
       <ul class="setting-list">
         <li>
           <BooleanSetting
@@ -112,7 +112,7 @@
           </BooleanSetting>
         </li>
         <li>
-          <h3>{{ $t('admin_dash.captcha.header') }}</h3>
+          <h3>{{ $t('admin_dash.instance.captcha_header') }}</h3>
         </li>
         <li>
           <BooleanSetting
@@ -150,7 +150,7 @@
             v-if="adminConfig[':pleroma']['Pleroma.Captcha'][':enabled'] && adminConfig[':pleroma']['Pleroma.Captcha'][':method'] === 'Pleroma.Captcha.Kocaptcha'"
             class="setting-list suboptions"
           >
-            <h4>{{ $t('admin_dash.kocaptcha') }}</h4>
+            <h4>{{ $t('admin_dash.instance.kocaptcha') }}</h4>
             <li>
               <StringSetting
                 source="admin"
diff --git a/src/components/settings_modal/admin_tabs/limits_tab.vue b/src/components/settings_modal/admin_tabs/limits_tab.vue
index 3f07c554..f7a70c97 100644
--- a/src/components/settings_modal/admin_tabs/limits_tab.vue
+++ b/src/components/settings_modal/admin_tabs/limits_tab.vue
@@ -1,7 +1,7 @@
 <template>
-  <div :label="$t('admin_dash.instance')">
+  <div :label="$t('admin_dash.tabs.limits')">
     <div class="setting-item">
-      <h2>{{ $t('admin_dash.arbitrary_limits') }}</h2>
+      <h2>{{ $t('admin_dash.limits.arbitrary_limits') }}</h2>
       <ul class="setting-list">
         <li>
           <h3>{{ $t('admin_dash.limits.posts') }}</h3>
@@ -19,6 +19,7 @@
           <IntegerSetting
             source="admin"
             path=":pleroma.:instance.:remote_limit"
+            expert="1"
             draft-mode
           >
             POST LIMIT (remote)
@@ -57,6 +58,15 @@
         <li>
           <h3>{{ $t('admin_dash.limits.users') }}</h3>
         </li>
+        <li>
+          <IntegerSetting
+            source="admin"
+            path=":pleroma.:instance.:max_pinned_statuses"
+            draft-mode
+          >
+            MAX PINNED POSTS
+          </IntegerSetting>
+        </li>
         <li>
           <IntegerSetting
             source="admin"
@@ -92,6 +102,7 @@
             source="admin"
             path=":pleroma.:instance.:max_remote_account_fields"
             draft-mode
+            expert="1"
           >
             MAX ACCOUNT FIELDS (remote)
           </IntegerSetting>
@@ -135,15 +146,6 @@
             MAX BANNER SIZE KiB
           </IntegerSetting>
         </li>
-        <li>
-          <IntegerSetting
-            source="admin"
-            path=":pleroma.:instance.:max_pinned_statuses"
-            draft-mode
-          >
-            MAX PINNED POSTS
-          </IntegerSetting>
-        </li>
       </ul>
     </div>
   </div>
diff --git a/src/components/settings_modal/settings_modal.vue b/src/components/settings_modal/settings_modal.vue
index 73e1524a..303050e4 100644
--- a/src/components/settings_modal/settings_modal.vue
+++ b/src/components/settings_modal/settings_modal.vue
@@ -8,7 +8,7 @@
     <div class="settings-modal-panel panel">
       <div class="panel-heading">
         <span class="title">
-          {{ $t('settings.settings') }}
+          {{ modalMode === 'user' ? $t('settings.settings') : $t('admin_dash.window_title') }}
         </span>
         <transition name="fade">
           <div
@@ -47,6 +47,7 @@
       </div>
       <div class="panel-footer settings-footer">
         <Popover
+          v-if="modalMode === 'user'"
           class="export"
           trigger="click"
           placement="top"
@@ -108,6 +109,18 @@
         >
           {{ $t("settings.expert_mode") }}
         </Checkbox>
+        <span v-if="modalMode === 'admin'">
+          <i18n-t keypath="admin_dash.wip_notice">
+            <template #adminFeLink>
+              <a
+                href="/pleroma/admin/#/login-pleroma"
+                target="_blank"
+              >
+                {{ $t("admin_dash.old_ui_link") }}
+              </a>
+            </template>
+          </i18n-t>
+        </span>
         <span
           id="unscrolled-content"
           class="extra-content"
diff --git a/src/components/settings_modal/settings_modal_admin_content.js b/src/components/settings_modal/settings_modal_admin_content.js
index c6c8837f..07d4cf2e 100644
--- a/src/components/settings_modal/settings_modal_admin_content.js
+++ b/src/components/settings_modal/settings_modal_admin_content.js
@@ -8,7 +8,7 @@ import LimitsTab from './admin_tabs/limits_tab.vue'
 import { library } from '@fortawesome/fontawesome-svg-core'
 import {
   faWrench,
-  faUser,
+  faHand,
   faFilter,
   faPaintBrush,
   faBell,
@@ -19,7 +19,7 @@ import {
 
 library.add(
   faWrench,
-  faUser,
+  faHand,
   faFilter,
   faPaintBrush,
   faBell,
diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue
index 16b55828..52c6ddf5 100644
--- a/src/components/settings_modal/settings_modal_admin_content.vue
+++ b/src/components/settings_modal/settings_modal_admin_content.vue
@@ -7,15 +7,15 @@
     :body-scroll-lock="bodyLock"
   >
     <div
-      :label="$t('admin_dash.instance')"
+      :label="$t('admin_dash.tabs.instance')"
       icon="wrench"
       data-tab-name="general"
     >
       <InstanceTab />
     </div>
     <div
-      :label="$t('admin_dash.limits')"
-      icon="wrench"
+      :label="$t('admin_dash.tabs.limits')"
+      icon="hand"
       data-tab-name="limits"
     >
       <LimitsTab />
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 10ba2ef8..8e36a7b8 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -832,6 +832,33 @@
       "frontend_version": "Frontend version"
     }
   },
+  "admin_dash": {
+    "window_title": "Administration",
+    "wip_notice": "This admin dashboard is experimental and WIP, {adminFeLink}.",
+    "old_ui_link": "old admin UI available here",
+    "tabs": {
+      "instance": "Instance",
+      "limits": "Limits"
+    },
+    "captcha": {
+      "native": "Native",
+      "kocaptcha": "KoCaptcha"
+    },
+    "instance": {
+      "instance": "Instance information",
+      "registrations": "User sign-ups",
+      "captcha_header": "CAPTCHA",
+      "kocaptcha": "KoCaptcha settings"
+    },
+    "limits": {
+      "arbitrary_limits": "Arbitrary limits",
+      "posts": "Post limits",
+      "uploads": "Attachments limits",
+      "users": "User profile limits",
+      "profile_fields": "Profile fields limits",
+      "user_uploads": "Profile media limits"
+    }
+  },
   "time": {
     "unit": {
       "days": "{0} day | {0} days",
-- 
cgit v1.2.3-70-g09d2


From 4c3af5c362574aad4d851990265ebc7252c6f990 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 27 Mar 2023 22:57:50 +0300
Subject: handle db config disabled case

---
 .../settings_modal/settings_modal_admin_content.js | 18 ++++++++--
 .../settings_modal_admin_content.vue               | 39 ++++++++++++++++++++++
 src/i18n/en.json                                   | 10 +++++-
 src/modules/adminSettings.js                       | 30 ++++++++++++++++-
 src/modules/users.js                               |  6 ----
 5 files changed, 93 insertions(+), 10 deletions(-)

(limited to 'src/components/settings_modal/settings_modal_admin_content.vue')

diff --git a/src/components/settings_modal/settings_modal_admin_content.js b/src/components/settings_modal/settings_modal_admin_content.js
index 07d4cf2e..1c239e59 100644
--- a/src/components/settings_modal/settings_modal_admin_content.js
+++ b/src/components/settings_modal/settings_modal_admin_content.js
@@ -9,7 +9,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'
 import {
   faWrench,
   faHand,
-  faFilter,
+  faLaptopCode,
   faPaintBrush,
   faBell,
   faDownload,
@@ -20,7 +20,7 @@ import {
 library.add(
   faWrench,
   faHand,
-  faFilter,
+  faLaptopCode,
   faPaintBrush,
   faBell,
   faDownload,
@@ -38,6 +38,9 @@ const SettingsModalAdminContent = {
     LimitsTab
   },
   computed: {
+    user () {
+      return this.$store.state.users.currentUser
+    },
     isLoggedIn () {
       return !!this.$store.state.users.currentUser
     },
@@ -46,6 +49,17 @@ const SettingsModalAdminContent = {
     },
     bodyLock () {
       return this.$store.state.interface.settingsModalState === 'visible'
+    },
+    adminDbLoaded () {
+      return this.$store.state.adminSettings.loaded
+    },
+    noDb () {
+      return this.$store.state.adminSettings.dbConfigEnabled === false
+    }
+  },
+  created () {
+    if (this.user.rights.admin) {
+      this.$store.dispatch('loadAdminStuff')
     }
   },
   methods: {
diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue
index 52c6ddf5..ae670a90 100644
--- a/src/components/settings_modal/settings_modal_admin_content.vue
+++ b/src/components/settings_modal/settings_modal_admin_content.vue
@@ -4,9 +4,40 @@
     class="settings_tab-switcher"
     :side-tab-bar="true"
     :scrollable-tabs="true"
+    :render-only-focused="true"
     :body-scroll-lock="bodyLock"
   >
     <div
+      v-if="noDb"
+      :label="$t('admin_dash.tabs.nodb')"
+      icon="exclamation-triangle"
+      data-tab-name="nodb-notice"
+    >
+      <div :label="$t('admin_dash.tabs.nodb')">
+        <div class="setting-item">
+          <h2>{{ $t('admin_dash.nodb.heading') }}</h2>
+          <i18n-t keypath="admin_dash.nodb.text">
+            <template #documentation>
+              <a
+                href="https://docs-develop.pleroma.social/backend/configuration/howto_database_config/"
+                target="_blank"
+              >
+                {{ $t("admin_dash.nodb.documentation") }}
+              </a>
+            </template>
+            <template #property>
+              <code>config :pleroma, configurable_from_database</code>
+            </template>
+            <template #value>
+              <code>true</code>
+            </template>
+          </i18n-t>
+          <p>{{ $t('admin_dash.nodb.text2') }}</p>
+        </div>
+      </div>
+    </div>
+    <div
+      v-if="adminDbLoaded"
       :label="$t('admin_dash.tabs.instance')"
       icon="wrench"
       data-tab-name="general"
@@ -14,12 +45,20 @@
       <InstanceTab />
     </div>
     <div
+      v-if="adminDbLoaded"
       :label="$t('admin_dash.tabs.limits')"
       icon="hand"
       data-tab-name="limits"
     >
       <LimitsTab />
     </div>
+    <div
+      :label="$t('admin_dash.tabs.frontends')"
+      icon="laptop-code"
+      data-tab-name="frontends"
+    >
+      <FrontendsTab />
+    </div>
   </tab-switcher>
 </template>
 
diff --git a/src/i18n/en.json b/src/i18n/en.json
index dd78d148..86ae7f06 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -845,8 +845,16 @@
     "reset_all": "Reset all",
     "commit_all": "Save all",
     "tabs": {
+      "nodb": "No DB Config",
       "instance": "Instance",
-      "limits": "Limits"
+      "limits": "Limits",
+      "frontends": "Front-ends"
+    },
+    "nodb": {
+      "heading": "Database config is disabled",
+      "text": "You need to change backend config files so that {property} is set to {value}, see more in {documentation}.",
+      "documentation": "documentation",
+      "text2": "Most configuration options will be unavailable."
     },
     "captcha": {
       "native": "Native",
diff --git a/src/modules/adminSettings.js b/src/modules/adminSettings.js
index 25fb8e50..fef73974 100644
--- a/src/modules/adminSettings.js
+++ b/src/modules/adminSettings.js
@@ -1,11 +1,13 @@
 import { set, get, cloneDeep, differenceWith, isEqual, flatten } from 'lodash'
 
 export const defaultState = {
+  loaded: false,
   needsReboot: null,
   config: null,
   modifiedPaths: null,
   descriptions: null,
-  draft: null
+  draft: null,
+  dbConfigEnabled: null
 }
 
 export const newUserFlags = {
@@ -17,7 +19,13 @@ const adminSettingsStorage = {
     ...cloneDeep(defaultState)
   },
   mutations: {
+    setInstanceAdminNoDbConfig (state) {
+      state.loaded = false
+      state.dbConfigEnabled = false
+    },
     updateAdminSettings (state, { config, modifiedPaths }) {
+      state.loaded = true
+      state.dbConfigEnabled = true
       state.config = config
       state.modifiedPaths = modifiedPaths
     },
@@ -40,6 +48,26 @@ const adminSettingsStorage = {
     }
   },
   actions: {
+    loadAdminStuff ({ state, rootState, dispatch, commit }) {
+      rootState.api.backendInteractor.fetchInstanceDBConfig()
+        .then(backendDbConfig => {
+          if (backendDbConfig.error) {
+            if (backendDbConfig.error.status === 400) {
+              backendDbConfig.error.json().then(errorJson => {
+                if (/configurable_from_database/.test(errorJson.error)) {
+                  commit('setInstanceAdminNoDbConfig')
+                }
+              })
+            }
+          } else {
+            dispatch('setInstanceAdminSettings', { backendDbConfig })
+          }
+        })
+      if (state.descriptions === null) {
+        rootState.api.backendInteractor.fetchInstanceConfigDescriptions()
+          .then(backendDescriptions => this.$store.dispatch('setInstanceAdminDescriptions', { backendDescriptions }))
+      }
+    },
     setInstanceAdminSettings ({ state, commit, dispatch }, { backendDbConfig }) {
       const config = state.config || {}
       const modifiedPaths = new Set()
diff --git a/src/modules/users.js b/src/modules/users.js
index 45cba334..a23f6d7d 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -564,12 +564,6 @@ const users = {
               user.domainMutes = []
               commit('setCurrentUser', user)
               commit('setServerSideStorage', user)
-              if (user.rights.admin) {
-                store.rootState.api.backendInteractor.fetchInstanceDBConfig()
-                  .then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig }))
-                store.rootState.api.backendInteractor.fetchInstanceConfigDescriptions()
-                  .then(backendDescriptions => dispatch('setInstanceAdminDescriptions', { backendDescriptions }))
-              }
               commit('addNewUsers', [user])
 
               dispatch('fetchEmoji')
-- 
cgit v1.2.3-70-g09d2


From ac75d051b720da2c47393de6b35663afe50d37cc Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 29 Mar 2023 23:26:57 +0300
Subject: better frontends tab, now you can set default frontend

---
 src/App.scss                                       |   1 +
 .../settings_modal/admin_tabs/frontends_tab.js     |   6 +
 .../settings_modal/admin_tabs/frontends_tab.scss   |   2 +-
 .../settings_modal/admin_tabs/frontends_tab.vue    | 204 +++++++++++++++------
 .../settings_modal/helpers/group_setting.js        |   1 -
 src/components/settings_modal/helpers/setting.js   |   4 +-
 .../helpers/shared_computed_object.js              |   3 +
 src/components/settings_modal/settings_modal.scss  |   3 +
 .../settings_modal/settings_modal_admin_content.js |   3 +
 .../settings_modal_admin_content.vue               |   1 +
 src/i18n/en.json                                   |  11 +-
 11 files changed, 177 insertions(+), 62 deletions(-)

(limited to 'src/components/settings_modal/settings_modal_admin_content.vue')

diff --git a/src/App.scss b/src/App.scss
index 149d640f..ef68ac50 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -646,6 +646,7 @@ option {
 }
 
 .cards-list {
+  list-style: none;
   display: grid;
   grid-auto-flow: row dense;
   grid-template-columns: 1fr 1fr;
diff --git a/src/components/settings_modal/admin_tabs/frontends_tab.js b/src/components/settings_modal/admin_tabs/frontends_tab.js
index a5d33cbe..a2c27c2a 100644
--- a/src/components/settings_modal/admin_tabs/frontends_tab.js
+++ b/src/components/settings_modal/admin_tabs/frontends_tab.js
@@ -51,6 +51,12 @@ const FrontendsTab = {
         .then((externalUser) => {
           this.$store.dispatch('loadFrontendsStuff')
         })
+    },
+    setDefault (frontend, suggestRef) {
+      const ref = suggestRef || frontend.refs[0]
+      const { name } = frontend
+
+      this.$store.commit('updateAdminDraft', { path: [':pleroma', ':frontends', ':primary'], value: { name, ref } })
     }
   }
 }
diff --git a/src/components/settings_modal/admin_tabs/frontends_tab.scss b/src/components/settings_modal/admin_tabs/frontends_tab.scss
index 1e1881ff..e3e04bc6 100644
--- a/src/components/settings_modal/admin_tabs/frontends_tab.scss
+++ b/src/components/settings_modal/admin_tabs/frontends_tab.scss
@@ -8,6 +8,6 @@
     word-wrap: nowrap;
     white-space: nowrap;
     overflow-x: hidden;
-    max-width: 80%;
+    max-width: 10em;
   }
 }
diff --git a/src/components/settings_modal/admin_tabs/frontends_tab.vue b/src/components/settings_modal/admin_tabs/frontends_tab.vue
index 48649dfb..71bbfa69 100644
--- a/src/components/settings_modal/admin_tabs/frontends_tab.vue
+++ b/src/components/settings_modal/admin_tabs/frontends_tab.vue
@@ -2,67 +2,157 @@
   <div class="frontends-tab" :label="$t('admin_dash.tabs.frontends')">
     <div class="setting-item">
       <h2>{{ $t('admin_dash.tabs.frontends') }}</h2>
-      <ul class="setting-list cards-list">
-        <li v-for="frontend in frontends" :key="frontend.name">
-          <strong>{{ frontend.name }}</strong>
-          <dl>
-            <dt>{{ $t('admin_dash.frontend.repository') }}</dt>
-            <dd><a :href="frontend.git">{{ frontend.git }}</a></dd>
-            <dt v-if="expertLevel">{{ $t('admin_dash.frontend.versions') }}</dt>
-            <dd v-if="expertLevel">{{ frontend.refs }}</dd>
-            <dt v-if="expertLevel">{{ $t('admin_dash.frontend.build_url') }}</dt>
-            <dd v-if="expertLevel">{{ frontend.build_url }}</dd>
-          </dl>
-          <div>
-            <span class="btn-group">
-              <button
-                class="button button-default btn"
-                type="button"
-                :title="$t('admin_dash.frontend.update')"
-                @click="update(frontend)"
-              >
-                {{
-                    frontend.installed
-                    ? $t('admin_dash.frontend.reinstall')
-                    : $t('admin_dash.frontend.install')
-                }}
-              </button>
-              <Popover
-                v-if="frontend.refs.length > 1"
-                trigger="click"
-                class="button-dropdown"
-                placement="bottom"
+      <p>{{ $t('admin_dash.frontend.wip_notice') }}</p>
+      <ul class="setting-list">
+        <li>
+          <h3>{{ $t('admin_dash.frontend.default_frontend') }}</h3>
+          <p>{{ $t('admin_dash.frontend.default_frontend_tip') }}</p>
+          <p>{{ $t('admin_dash.frontend.default_frontend_tip2') }}</p>
+        </li>
+        <li>
+          <StringSetting path=":pleroma.:frontends.:primary.name">
+            NAME
+          </StringSetting>
+        </li>
+        <li>
+          <StringSetting path=":pleroma.:frontends.:primary.ref">
+            REF
+          </StringSetting>
+        </li>
+        <li>
+          <GroupSetting path=":pleroma.:frontends.:primary"/>
+        </li>
+      </ul>
+      <div class="setting-list">
+        <h3>{{ $t('admin_dash.frontend.available_frontends') }}</h3>
+        <ul class="cards-list">
+          <li v-for="frontend in frontends" :key="frontend.name">
+            <strong>{{ frontend.name }}</strong>
+            {{ ' ' }}
+            <span v-if="adminDraft[':pleroma'][':frontends'][':primary'].name === frontend.name">
+              <i18n-t
+                keypath="admin_dash.frontend.is_default"
+                v-if="adminDraft[':pleroma'][':frontends'][':primary'].ref === frontend.refs[0]"
+              />
+              <i18n-t
+                keypath="admin_dash.frontend.is_default_custom"
+                v-else
               >
-                <template #content>
-                  <div class="dropdown-menu">
+                <template #version>
+                  <code>{{ adminDraft[':pleroma'][':frontends'][':primary'].ref }}</code>
+                </template>
+              </i18n-t>
+            </span>
+            <dl>
+              <dt>{{ $t('admin_dash.frontend.repository') }}</dt>
+              <dd><a :href="frontend.git" target="_blank">{{ frontend.git }}</a></dd>
+              <template v-if="expertLevel">
+                <dt>{{ $t('admin_dash.frontend.versions') }}</dt>
+                <dd v-for="ref in frontend.refs" :key="ref"><code>{{ ref }}</code></dd>
+              </template>
+              <dt v-if="expertLevel">{{ $t('admin_dash.frontend.build_url') }}</dt>
+              <dd v-if="expertLevel"><a :href="frontend.build_url" target="_blank">{{ frontend.build_url }}</a></dd>
+            </dl>
+            <div>
+              <span class="btn-group">
+                <button
+                  class="button button-default btn"
+                  type="button"
+                  :title="$t('admin_dash.frontend.update')"
+                  @click="update(frontend)"
+                >
+                  {{
+                      frontend.installed
+                      ? $t('admin_dash.frontend.reinstall')
+                      : $t('admin_dash.frontend.install')
+                  }}
+                </button>
+                <Popover
+                  v-if="frontend.refs.length > 1"
+                  trigger="click"
+                  class="button-dropdown"
+                  placement="bottom"
+                >
+                  <template #content>
+                    <div class="dropdown-menu">
+                      <button
+                        v-for="ref in frontend.refs"
+                        :key="ref"
+                        class="button-default dropdown-item"
+                        @click="update(frontend, ref)"
+                      >
+                        <i18n-t keypath="admin_dash.frontend.install_version">
+                          <template #version>
+                            <code>{{ ref }}</code>
+                          </template>
+                        </i18n-t>
+                      </button>
+                    </div>
+                  </template>
+                  <template #trigger>
                     <button
-                      v-for="ref in frontend.refs"
-                      :key="ref"
-                      class="button-default dropdown-item"
-                      @click="update(frontend, ref)"
+                      class="button button-default btn dropdown-button"
+                      type="button"
+                      :title="$t('admin_dash.frontend.update')"
                     >
-                      <i18n-t keypath="admin_dash.frontend.install_version">
-                        <template #version>
-                          <code>{{ ref }}</code>
-                        </template>
-                      </i18n-t>
+                      <FAIcon icon="chevron-down" />
                     </button>
-                  </div>
-                </template>
-                <template #trigger>
-                  <button
-                    class="button button-default btn"
-                    type="button"
-                    :title="$t('admin_dash.frontend.update')"
-                  >
-                    <FAIcon icon="chevron-down" />
-                  </button>
-                </template>
-              </Popover>
-            </span>
-          </div>
-        </li>
-      </ul>
+                  </template>
+                </Popover>
+              </span>
+              <span class="btn-group" v-if="frontend.name !== 'admin-fe'">
+                <button
+                  class="button button-default btn"
+                  type="button"
+                  :disabled="
+                             adminDraft[':pleroma'][':frontends'][':primary'].name === frontend.name &&
+                             adminDraft[':pleroma'][':frontends'][':primary'].ref === frontend.refs[0]
+                             "
+                  :title="$t('admin_dash.frontend.update')"
+                  @click="setDefault(frontend)"
+                >
+                  {{
+                      $t('admin_dash.frontend.set_default')
+                  }}
+                </button>
+                {{ ' ' }}
+                <Popover
+                  v-if="frontend.refs.length > 1"
+                  trigger="click"
+                  class="button-dropdown"
+                  placement="bottom"
+                >
+                  <template #content>
+                    <div class="dropdown-menu">
+                      <button
+                        v-for="ref in frontend.refs.slice(1)"
+                        :key="ref"
+                        class="button-default dropdown-item"
+                        @click="setDefault(frontend, ref)"
+                      >
+                        <i18n-t keypath="admin_dash.frontend.set_default_version">
+                          <template #version>
+                            <code>{{ ref }}</code>
+                          </template>
+                        </i18n-t>
+                      </button>
+                    </div>
+                  </template>
+                  <template #trigger>
+                    <button
+                      class="button button-default btn dropdown-button"
+                      type="button"
+                      :title="$t('admin_dash.frontend.update')"
+                    >
+                      <FAIcon icon="chevron-down" />
+                    </button>
+                  </template>
+                </Popover>
+              </span>
+            </div>
+          </li>
+        </ul>
+      </div>
     </div>
   </div>
 </template>
diff --git a/src/components/settings_modal/helpers/group_setting.js b/src/components/settings_modal/helpers/group_setting.js
index 12a49000..23a2a202 100644
--- a/src/components/settings_modal/helpers/group_setting.js
+++ b/src/components/settings_modal/helpers/group_setting.js
@@ -7,7 +7,6 @@ export default {
   computed: {
     ...Setting.computed,
     isDirty () {
-      console.log(this.state, this.draft)
       return !isEqual(this.state, this.draft)
     }
   }
diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js
index d2e1a6f4..4f0be448 100644
--- a/src/components/settings_modal/helpers/setting.js
+++ b/src/components/settings_modal/helpers/setting.js
@@ -61,7 +61,7 @@ export default {
       // TODO allow passing shared draft object?
       get () {
         if (this.realSource === 'admin') {
-          return get(this.$store.state.adminSettings.draft, this.path)
+          return get(this.$store.state.adminSettings.draft, this.canonPath)
         } else {
           return this.localDraft
         }
@@ -75,7 +75,7 @@ export default {
       }
     },
     state () {
-      const value = get(this.configSource, this.path)
+      const value = get(this.configSource, this.canonPath)
       if (value === undefined) {
         return this.defaultState
       } else {
diff --git a/src/components/settings_modal/helpers/shared_computed_object.js b/src/components/settings_modal/helpers/shared_computed_object.js
index d02db542..bb3d36ac 100644
--- a/src/components/settings_modal/helpers/shared_computed_object.js
+++ b/src/components/settings_modal/helpers/shared_computed_object.js
@@ -10,6 +10,9 @@ const SharedComputedObject = () => ({
   },
   adminConfig () {
     return this.$store.state.adminSettings.config
+  },
+  adminDraft () {
+    return this.$store.state.adminSettings.draft
   }
 })
 
diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss
index 98de736b..49ef83e0 100644
--- a/src/components/settings_modal/settings_modal.scss
+++ b/src/components/settings_modal/settings_modal.scss
@@ -43,6 +43,9 @@
 
       .btn {
         min-height: 2em;
+      }
+
+      .btn:not(.dropdown-button) {
         padding: 0 2em;
       }
     }
diff --git a/src/components/settings_modal/settings_modal_admin_content.js b/src/components/settings_modal/settings_modal_admin_content.js
index b7c0de57..f94721ec 100644
--- a/src/components/settings_modal/settings_modal_admin_content.js
+++ b/src/components/settings_modal/settings_modal_admin_content.js
@@ -51,6 +51,9 @@ const SettingsModalAdminContent = {
     adminDbLoaded () {
       return this.$store.state.adminSettings.loaded
     },
+    adminDescriptionsLoaded () {
+      return this.$store.state.adminSettings.descriptions !== null
+    },
     noDb () {
       return this.$store.state.adminSettings.dbConfigEnabled === false
     }
diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue
index ae670a90..a7a2ac9a 100644
--- a/src/components/settings_modal/settings_modal_admin_content.vue
+++ b/src/components/settings_modal/settings_modal_admin_content.vue
@@ -1,5 +1,6 @@
 <template>
   <tab-switcher
+    v-if="adminDescriptionsLoaded && (noDb || adminDbLoaded)"
     ref="tabSwitcher"
     class="settings_tab-switcher"
     :side-tab-bar="true"
diff --git a/src/i18n/en.json b/src/i18n/en.json
index ede5d494..6ae31ee8 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -879,8 +879,17 @@
       "versions": "Available versions",
       "build_url": "Build URL",
       "reinstall": "Reinstall",
+      "is_default": "(Default)",
+      "is_default_custom": "(Default, version: {version})",
       "install": "Install",
-      "install_version": "Install version {version}"
+      "install_version": "Install version {version}",
+      "set_default": "Set default",
+      "set_default_version": "Set version {version} as default",
+      "wip_notice": "Please note that this section is a WIP and lacks certain features as backend implementation of front-end management is incomplete.",
+      "default_frontend": "Default front-end",
+      "default_frontend_tip": "Default front-end will be shown to all users. Currently there's no way to for a user to select personal front-end. If you switch away from PleromaFE you'll most likely have to use old and buggy AdminFE to do instance configuration until we replace it.",
+      "default_frontend_tip2": "WIP: Since Pleroma backend doesn't properly list all installed frontends you'll have to enter name and reference manually. List below provides shortcuts to fill the values.",
+      "available_frontends": "Available for install"
     }
   },
   "time": {
-- 
cgit v1.2.3-70-g09d2

