diff --git a/changelog.d/admin_tab.add b/changelog.d/admin_tab.add new file mode 100644 index 000000000..421ce57cd --- /dev/null +++ b/changelog.d/admin_tab.add @@ -0,0 +1 @@ +Most of the remaining AdminFE tabs into Admin Dashboard diff --git a/src/App.scss b/src/App.scss index ee1654bb7..57faf4aa3 100644 --- a/src/App.scss +++ b/src/App.scss @@ -513,6 +513,12 @@ nav { } } +label { + &.-disabled { + color: var(--textFaint); + } +} + input, textarea { border: none; @@ -553,6 +559,10 @@ textarea { &[disabled="disabled"], &.disabled { cursor: not-allowed; + color: var(--textFaint); + + /* stylelint-disable-next-line declaration-no-important */ + background-color: transparent !important; } &[type="range"] { @@ -578,6 +588,8 @@ textarea { & + label::before { opacity: 0.5; } + + background-color: var(--background); } + label::before { @@ -677,7 +689,8 @@ option { list-style: none; display: grid; grid-auto-flow: row dense; - grid-template-columns: 1fr 1fr; + grid-template-columns: repeat(auto-fit, minmax(20em, 1fr)); + grid-gap: 0.5em; li { border: 1px solid var(--border); @@ -692,13 +705,16 @@ option { display: inline-flex; vertical-align: middle; + .Select select { + line-height: 1; + } + > *, > * .button-default { --_roundness-left: 0; --_roundness-right: 0; position: relative; - flex: 1 1 auto; } > *:first-child, diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue index c8bba4c44..1e0f5ad05 100644 --- a/src/components/checkbox/checkbox.vue +++ b/src/components/checkbox/checkbox.vue @@ -1,7 +1,7 @@ + + + {{ $t('admin_dash.auth.MFA') }} + + + {{ $t('admin_dash.auth.TOTP') }} + + + + + + + + + + + {{ $t('admin_dash.auth.backup_codes') }} + + + + + + + + + + + + {{ $t('admin_dash.auth.OAuth') }} + + + + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.auth.LDAP') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/emoji_tab.js b/src/components/settings_modal/admin_tabs/emoji_tab.js index d8f769e0b..7c137e35f 100644 --- a/src/components/settings_modal/admin_tabs/emoji_tab.js +++ b/src/components/settings_modal/admin_tabs/emoji_tab.js @@ -10,6 +10,22 @@ import ModifiedIndicator from '../helpers/modified_indicator.vue' import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue' import { useInterfaceStore } from 'src/stores/interface' +import SharedComputedObject from '../helpers/shared_computed_object.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faArrowsRotate, + faFolderOpen, + faServer, + faDownload +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faArrowsRotate, + faFolderOpen, + faDownload, + faServer +) + const EmojiTab = { components: { TabSwitcher, @@ -44,10 +60,12 @@ const EmojiTab = { }, computed: { + ...SharedComputedObject(), pack () { return this.packName !== '' ? this.knownPacks[this.packName] : undefined }, packMeta () { + if (this.packName === '') return {} if (this.editedMetadata[this.packName] === undefined) { this.editedMetadata[this.packName] = clone(this.pack.pack) } @@ -98,8 +116,6 @@ const EmojiTab = { return Promise.reject(resp) } }).then(() => { - this.$refs.createPackPopover.hidePopover() - this.packName = this.newPackName this.newPackName = '' }) @@ -205,8 +221,6 @@ const EmojiTab = { for (const pack in this.knownRemotePacks[inst]) { this.sortPackFiles(`${pack}@${inst}`) } - - this.$refs.remotePackPopover.hidePopover() }) .catch(data => { this.displayError(data) @@ -223,8 +237,6 @@ const EmojiTab = { .then(data => data.json()) .then(resp => { if (resp === 'ok') { - this.$refs.downloadPackPopover.hidePopover() - return this.refreshPackList() } else { this.displayError(resp.error) @@ -242,8 +254,6 @@ const EmojiTab = { .then(data => data.json()) .then(resp => { if (resp === 'ok') { - this.$refs.additionalRemotePopover.hidePopover() - return this.refreshPackList() } else { this.displayError(resp.error) @@ -262,8 +272,6 @@ const EmojiTab = { .then(data => data.json()) .then(resp => { if (resp === 'ok') { - this.$refs.additionalRemotePopover.hidePopover() - return this.refreshPackList() } else { this.displayError(resp.error) diff --git a/src/components/settings_modal/admin_tabs/emoji_tab.scss b/src/components/settings_modal/admin_tabs/emoji_tab.scss index eefada63a..327d0f376 100644 --- a/src/components/settings_modal/admin_tabs/emoji_tab.scss +++ b/src/components/settings_modal/admin_tabs/emoji_tab.scss @@ -1,10 +1,48 @@ -.emoji-tab { - .btn-group .btn:not(:first-child) { - margin-left: 0.5em; +.EmojiTab { + .setting-list { + padding-left: 0.75em; } - .pack-info-wrapper { + .toolbar { + display: flex; + flex-wrap: wrap; + gap: 0.5em; + + .header-buttons { + display: flex; + flex: 1 0 auto; + justify-content: end; + + &:not(.btn-group) { + gap: 0.5em; + } + + .header-text { + flex: 1 0 auto; + } + } + + .button-default { + flex: 0 0 auto; + padding: 0.5em; + font-size: 1rem; + } + } + + .selector-buttons, + .meta-buttons { + display: flex; + flex-wrap: wrap; + gap: 0.5em; + } + + h5 { margin-top: 1em; + margin-bottom: 0.25em; + } + + h3.toolbar { + align-items: end; } .emoji-info-input { @@ -18,8 +56,8 @@ } .emoji { - width: 32px; - height: 32px; + width: 2em; + height: 2em; } .emoji-unsaved { @@ -30,6 +68,14 @@ display: flex; flex-wrap: wrap; gap: 1em; + + .placeholder { + background: var(--textFaint); + border-radius: 0.5em; + width: 2em; + height: 2em; + opacity: 0.5; + } } } diff --git a/src/components/settings_modal/admin_tabs/emoji_tab.vue b/src/components/settings_modal/admin_tabs/emoji_tab.vue index 9095192fe..fcf03dd97 100644 --- a/src/components/settings_modal/admin_tabs/emoji_tab.vue +++ b/src/components/settings_modal/admin_tabs/emoji_tab.vue @@ -1,168 +1,75 @@ - {{ $t('admin_dash.tabs.emoji') }} + + + {{ $t('admin_dash.emoji.emoji_packs') }} + - - {{ $t('admin_dash.emoji.global_actions') }} - - + - {{ $t('admin_dash.emoji.reload') }} - - - {{ $t('admin_dash.emoji.importFS') }} - - - - - - {{ $t('admin_dash.emoji.remote_packs') }} - - - - - {{ $t('admin_dash.emoji.remote_pack_instance') }} - - - {{ $t('admin_dash.emoji.do_list') }} - - - - - - - - - - - - {{ $t('admin_dash.emoji.new_pack_name') }} - - Import pack from URL - - - Import - - Import pack from a file - - - Import - - - - - - - - {{ $t('admin_dash.emoji.emoji_packs') }} - - - {{ $t('admin_dash.emoji.edit_pack') }} - - - - {{ $t('admin_dash.emoji.emoji_pack') }} - - - {{ listPackName }} - - - - - {{ $t('admin_dash.emoji.create_pack') }} + + {{ $t('admin_dash.emoji.reload_short') }} + + + + {{ $t('admin_dash.emoji.remote_packs_short') }} + + + + + {{ $t('admin_dash.emoji.remote_pack_instance') }} + + + {{ $t('admin_dash.emoji.do_list') }} + + + + + + + + + + {{ $t('admin_dash.emoji.import_pack_short') }} + + + {{ $t('admin_dash.emoji.new_pack_name') }} @@ -171,94 +78,252 @@ :placeholder="$t('admin_dash.emoji.new_pack_name')" class="input" > + Import pack from URL + - {{ $t('admin_dash.emoji.create') }} + Import + + Import pack from a file + + + Import - - + + + + + {{ $t('admin_dash.emoji.edit_pack') }} + + + + {{ $t('admin_dash.emoji.delete_pack') }} - - - - - - {{ $t('admin_dash.emoji.description') }} - + + {{ $t('admin_dash.emoji.delete_confirm', [packName]) }} + + - - - - - - {{ $t('admin_dash.emoji.homepage') }} - + + {{ $t('admin_dash.emoji.download_pack') }} - - - - - - {{ $t('admin_dash.emoji.fallback_src') }} - + + + {{ $t('admin_dash.emoji.downloading_pack', [packName]) }} + + + + + {{ $t('admin_dash.emoji.download_as_name') }} + + - - - - - - {{ $t('admin_dash.emoji.fallback_sha256') }} + + {{ $t('admin_dash.emoji.replace_warning') }} + + - - - - - + {{ $t('admin_dash.emoji.download') }} + + + + + + + + + + - {{ $t('admin_dash.emoji.share') }} - + {{ $t('admin_dash.emoji.emoji_pack') }} + + + {{ listPackName }} + + + + + + {{ $t('admin_dash.emoji.create_pack') }} + + + + + {{ $t('admin_dash.emoji.new_pack_name') }} + + + {{ $t('admin_dash.emoji.create') }} + + + + + + + + {{ $t('admin_dash.emoji.metadata') }} + + + + + + + {{ $t('admin_dash.emoji.description') }} - - + + + + + + + {{ $t('admin_dash.emoji.homepage') }} + + + + + + + + {{ $t('admin_dash.emoji.fallback_src') }} + + + + + + + + {{ $t('admin_dash.emoji.fallback_sha256') }} + + + + + + + {{ $t('admin_dash.emoji.share') }} + + + + {{ $t('admin_dash.emoji.revert_meta') }} - - - {{ $t('admin_dash.emoji.delete_pack') }} - - - {{ $t('admin_dash.emoji.delete_confirm', [packName]) }} - - - - - {{ $t('admin_dash.emoji.download_pack') }} - - - - {{ $t('admin_dash.emoji.downloading_pack', [packName]) }} - - - - - {{ $t('admin_dash.emoji.download_as_name') }} - - - - - {{ $t('admin_dash.emoji.replace_warning') }} - - - - - {{ $t('admin_dash.emoji.download') }} - - - - - - - - - - - - - {{ $t('admin_dash.emoji.files') }} - - - - - - - - - - - - - - - - - + + + + {{ $t('admin_dash.emoji.files') }} + + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.emoji.advanced') }} + + + {{ $t('admin_dash.emoji.importFS') }} + diff --git a/src/components/settings_modal/admin_tabs/federation_tab.js b/src/components/settings_modal/admin_tabs/federation_tab.js new file mode 100644 index 000000000..97b4e0040 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/federation_tab.js @@ -0,0 +1,34 @@ +import BooleanSetting from '../helpers/boolean_setting.vue' +import IntegerSetting from '../helpers/integer_setting.vue' +import StringSetting from '../helpers/string_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' +import ListTupleSetting from '../helpers/list_tuple_setting.vue' +import MapSetting from '../helpers/map_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' + +const FederationTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + IntegerSetting, + StringSetting, + AttachmentSetting, + ListSetting, + ListTupleSetting, + GroupSetting, + MapSetting + }, + computed: { + ...SharedComputedObject() + } +} + +export default FederationTab diff --git a/src/components/settings_modal/admin_tabs/federation_tab.vue b/src/components/settings_modal/admin_tabs/federation_tab.vue new file mode 100644 index 000000000..9af338653 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/federation_tab.vue @@ -0,0 +1,68 @@ + + + + {{ $t('admin_dash.federation.global') }} + + + + + + + + + + + + {{ $t('admin_dash.federation.restrictions') }} + + + + + + + + + {{ $t('admin_dash.federation.activitypub') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/frontends_tab.js b/src/components/settings_modal/admin_tabs/frontends_tab.js index a9a4777da..c63e76214 100644 --- a/src/components/settings_modal/admin_tabs/frontends_tab.js +++ b/src/components/settings_modal/admin_tabs/frontends_tab.js @@ -44,10 +44,10 @@ const FrontendsTab = { } }, computed: { + ...SharedComputedObject(), frontends () { return this.$store.state.adminSettings.frontends - }, - ...SharedComputedObject() + } }, methods: { canInstall (frontend) { diff --git a/src/components/settings_modal/admin_tabs/frontends_tab.scss b/src/components/settings_modal/admin_tabs/frontends_tab.scss index 3bc347087..27c1fdc55 100644 --- a/src/components/settings_modal/admin_tabs/frontends_tab.scss +++ b/src/components/settings_modal/admin_tabs/frontends_tab.scss @@ -1,8 +1,24 @@ -.frontends-tab { +.FrontendsTab { .cards-list { padding: 0; } + li.frontend-card { + display: flex; + margin: 0; + flex-direction: column; + } + + .frontend-buttons { + margin-top: 0.5em; + display: flex; + justify-content: end; + gap: 0.5em; + flex-wrap: wrap; + flex: 1 0 auto; + align-items: end; + } + .relative { position: relative; } @@ -16,10 +32,26 @@ inset: 0; } + h5 { + margin: 0; + font-size: 1.15em + } + + dl { + margin-left: 1em; + } + + dt { + margin-top: 0.5em; + text-overflow: ellipsis; + white-space: nowrap; + overflow-x: hidden; + } + dd { text-overflow: ellipsis; white-space: nowrap; overflow-x: hidden; - 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 954d9ef51..750a70165 100644 --- a/src/components/settings_modal/admin_tabs/frontends_tab.vue +++ b/src/components/settings_modal/admin_tabs/frontends_tab.vue @@ -1,17 +1,17 @@ - {{ $t('admin_dash.tabs.frontends') }} + {{ $t('admin_dash.frontend.title') }} {{ $t('admin_dash.frontend.wip_notice') }} - {{ $t('admin_dash.frontend.default_frontend') }} + {{ $t('admin_dash.frontend.default_frontend') }} {{ $t('admin_dash.frontend.default_frontend_tip') }} @@ -38,13 +38,14 @@ v-if="working" class="overlay" /> - {{ $t('admin_dash.frontend.available_frontends') }} + {{ $t('admin_dash.frontend.available_frontends') }} - {{ frontend.name }} + {{ frontend.name }} {{ ' ' }} {{ frontend.build_url }} - + ({ + label: option.replace(':tlsv', 'TLS v'), + value: option + }))) + }, + } +} + +export default HTTPTab diff --git a/src/components/settings_modal/admin_tabs/http_tab.vue b/src/components/settings_modal/admin_tabs/http_tab.vue new file mode 100644 index 000000000..7a2e7b60a --- /dev/null +++ b/src/components/settings_modal/admin_tabs/http_tab.vue @@ -0,0 +1,126 @@ + + + + {{ $t('admin_dash.http.outbound') }} + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.http.incoming') }} + + {{ $t('admin_dash.http.cors') }} + + + + + + + + + + + + + + + + {{ $t('admin_dash.http.security') }} + + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.http.web_cache_ttl') }} + {{ $t('admin_dash.http.web_cache_ttl_description') }} + + + + + + + + {{ $t('admin_dash.http.web_push') }} + {{ $t('admin_dash.http.web_push_description') }} + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/instance_tab.js b/src/components/settings_modal/admin_tabs/instance_tab.js index b07bafe8f..ddbd58a88 100644 --- a/src/components/settings_modal/admin_tabs/instance_tab.js +++ b/src/components/settings_modal/admin_tabs/instance_tab.js @@ -2,18 +2,15 @@ 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 ColorSetting from '../helpers/color_setting.vue' import GroupSetting from '../helpers/group_setting.vue' import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' +import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue' +import MapSetting from '../helpers/map_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 -) +import { get } from 'lodash' const InstanceTab = { provide () { @@ -27,11 +24,29 @@ const InstanceTab = { ChoiceSetting, IntegerSetting, StringSetting, + ColorSetting, AttachmentSetting, + ListSetting, + PWAManifestIconsSetting, + MapSetting, GroupSetting }, computed: { - ...SharedComputedObject() + ...SharedComputedObject(), + providersOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, [':pleroma', 'Pleroma.Web.Metadata', ':providers']) + return new Set(desc.suggestions.map(option => ({ + label: option.replace('Pleroma.Web.Metadata.Providers.', ''), + value: option + }))) + }, + limitLocalContentOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, [':pleroma', ':instance', ':limit_to_local_content']) + return new Set(desc.suggestions.map(option => ({ + label: option !== 'false' ? this.$t('admin_dash.instance.' + option) : this.$t('general.no'), + value: option + }))) + } } } diff --git a/src/components/settings_modal/admin_tabs/instance_tab.vue b/src/components/settings_modal/admin_tabs/instance_tab.vue index 32e8df259..89d27315a 100644 --- a/src/components/settings_modal/admin_tabs/instance_tab.vue +++ b/src/components/settings_modal/admin_tabs/instance_tab.vue @@ -1,17 +1,13 @@ - {{ $t('admin_dash.instance.instance') }} + {{ $t('admin_dash.instance.instance') }} - - - + + @@ -22,87 +18,63 @@ + + + + + + + + {{ $t('admin_dash.instance.branding') }} + + + + + + + + + + + + + + - - - {{ $t('admin_dash.instance.registrations') }} + {{ $t('admin_dash.instance.rich_metadata') }} - - - - - - + - - - - - - - - - - - - - - - {{ $t('admin_dash.instance.captcha_header') }} - - - - - - - - - - {{ $t('admin_dash.instance.kocaptcha') }} - - - - - - - - - + - {{ $t('admin_dash.instance.access') }} + {{ $t('admin_dash.instance.access') }} diff --git a/src/components/settings_modal/admin_tabs/job_queues_tab.js b/src/components/settings_modal/admin_tabs/job_queues_tab.js new file mode 100644 index 000000000..b0f583c55 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/job_queues_tab.js @@ -0,0 +1,34 @@ +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 TupleSetting from '../helpers/tuple_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' + +const JobQueuesTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting, + TupleSetting, + AttachmentSetting, + GroupSetting, + ListSetting + }, + computed: { + ...SharedComputedObject() + } +} + +export default JobQueuesTab diff --git a/src/components/settings_modal/admin_tabs/job_queues_tab.vue b/src/components/settings_modal/admin_tabs/job_queues_tab.vue new file mode 100644 index 000000000..f156a6fa5 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/job_queues_tab.vue @@ -0,0 +1,199 @@ + + + + {{ $t('admin_dash.job_queues.Oban') }} + + + + {{ $t('admin_dash.job_queues.queues') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Gun.title') }} + + + {{ $t('admin_dash.job_queues.Gun.connections_pools') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Gun.pools.title') }} + + + {{ $t('admin_dash.job_queues.Gun.pools.default') }} + + + + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Gun.pools.federation') }} + + + + + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Gun.pools.rich_media') }} + + + + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Gun.pools.media') }} + + + + + + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Hackney.title') }} + + + {{ $t('admin_dash.job_queues.Hackney.federation') }} + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Hackney.media') }} + + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Hackney.rich_media') }} + + + + + + + + + + + + {{ $t('admin_dash.job_queues.Hackney.upload') }} + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/limits_tab.js b/src/components/settings_modal/admin_tabs/limits_tab.js index acf7d3436..c1126f49c 100644 --- a/src/components/settings_modal/admin_tabs/limits_tab.js +++ b/src/components/settings_modal/admin_tabs/limits_tab.js @@ -4,14 +4,6 @@ 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 = { components: { diff --git a/src/components/settings_modal/admin_tabs/limits_tab.vue b/src/components/settings_modal/admin_tabs/limits_tab.vue index ef4b9271d..04e5334da 100644 --- a/src/components/settings_modal/admin_tabs/limits_tab.vue +++ b/src/components/settings_modal/admin_tabs/limits_tab.vue @@ -1,10 +1,10 @@ - {{ $t('admin_dash.limits.arbitrary_limits') }} + {{ $t('admin_dash.limits.arbitrary_limits') }} - {{ $t('admin_dash.limits.posts') }} + {{ $t('admin_dash.limits.posts') }} - {{ $t('admin_dash.limits.uploads') }} + {{ $t('admin_dash.limits.uploads') }} - {{ $t('admin_dash.limits.users') }} + {{ $t('admin_dash.limits.users') }} - {{ $t('admin_dash.limits.profile_fields') }} + {{ $t('admin_dash.limits.profile_fields') }} - {{ $t('admin_dash.limits.user_uploads') }} + {{ $t('admin_dash.limits.user_uploads') }} + + {{ $t('admin_dash.limits.other') }} + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/links_tab.js b/src/components/settings_modal/admin_tabs/links_tab.js new file mode 100644 index 000000000..026b099a5 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/links_tab.js @@ -0,0 +1,109 @@ +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 GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' + +import Checkbox from 'src/components/checkbox/checkbox.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' +import { get } from 'lodash' + +const LinksTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting, + AttachmentSetting, + GroupSetting, + ListSetting, + Checkbox + }, + computed: { + classIsPresent () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':class'] !== false + }, + relIsPresent () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':rel'] !== false + }, + truncateIsPresent () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':truncate'] !== false + }, + truncateDescription () { + return get(this.$store.state.adminSettings.descriptions, [':pleroma', 'Pleroma.Formatter', ':truncate']) + }, + ttlSettersOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, ':pleroma.:rich_media.:ttl_setters') + return new Set(desc.suggestions.map(option => ({ + label: option.replace('Pleroma.Web.RichMedia.Parser.TTL.', ''), + value: option + }))) + }, + parsersOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, ':pleroma.:rich_media.:parsers') + return new Set(desc.suggestions.map(option => ({ + label: option.replace('Pleroma.Web.RichMedia.Parsers.', ''), + value: option + }))) + }, + validateTLDOptions () { + return [{ + label: this.$t('general.yes'), + value: true + }, { + label: this.$t('general.no'), + value: false + }, { + label: this.$t('admin_dash.links.no_scheme'), + value: ':no_scheme' + }] + }, + mediaProxyEnabled () { + return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':enabled'] + }, + mediaInvalidationProvider () { + return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':invalidation'][':provider'] + }, + ...SharedComputedObject() + }, + methods: { + checkRel (e) { + this.$store.commit( + 'updateAdminDraft', + { + path: [':pleroma','Pleroma.Formatter',':rel'], + value: e ? '' : false + } + ) + }, + checkClass (e) { + this.$store.commit( + 'updateAdminDraft', + { + path: [':pleroma','Pleroma.Formatter',':class'], + value: e ? '' : false + } + ) + }, + checkTruncate (e) { + this.$store.commit( + 'updateAdminDraft', + { + path: [':pleroma','Pleroma.Formatter',':truncate'], + value: e ? 20 : false + } + ) + } + } +} + +export default LinksTab diff --git a/src/components/settings_modal/admin_tabs/links_tab.scss b/src/components/settings_modal/admin_tabs/links_tab.scss new file mode 100644 index 000000000..8946ccc0a --- /dev/null +++ b/src/components/settings_modal/admin_tabs/links_tab.scss @@ -0,0 +1,26 @@ +.LinksTab { + // awkward "disable = false" backend options + .weird-options { + .checkbox { + margin: 0; + } + } + + .setting-list.suboptions.weird-suboptions { + display: flex; + flex-direction: column; + gap: 0.5em; + margin: 0; + + li { + margin: 0; + display: flex; + } + + .GroupSetting { + display: inline-block; + margin: 0; + padding: 0; + } + } +} diff --git a/src/components/settings_modal/admin_tabs/links_tab.vue b/src/components/settings_modal/admin_tabs/links_tab.vue new file mode 100644 index 000000000..9c661b209 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/links_tab.vue @@ -0,0 +1,146 @@ + + + + {{ $t('admin_dash.links.link_previews') }} + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.links.link_formatter') }} + + + + + + class + + + + + + + + + + + + + rel + + + + + + + + + + + + + + + + + + + + + + + {{ truncateDescription.label }} + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/mailer_tab.js b/src/components/settings_modal/admin_tabs/mailer_tab.js new file mode 100644 index 000000000..b67dc58ac --- /dev/null +++ b/src/components/settings_modal/admin_tabs/mailer_tab.js @@ -0,0 +1,63 @@ +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 GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' + +const MailerTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting, + AttachmentSetting, + GroupSetting + }, + computed: { + adaptersLabels () { + const prefix = 'Swoosh.Adapters.' + const descriptions = this.$store.state.adminSettings.descriptions + const options = descriptions[':pleroma']['Pleroma.Emails.Mailer'][':adapter'].suggestions + + return Object.fromEntries(options.map(value => [ + value, value.replace(prefix, '') + ])) + }, + startTLSLabels () { + return { + ':always': this.$t('admin_dash.generic_enforcement.always'), + ':if_available': this.$t('admin_dash.generic_enforcement.if_available'), + ':never': this.$t('admin_dash.generic_enforcement.never') + } + // return Object.fromEntries(options.map(value => [ + // value, value.replace(prefix, '') + // ])) + }, + adapter () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Emails.Mailer'][':adapter'] + }, + mailerEnabled () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Emails.Mailer'][':enabled'] + }, + ...SharedComputedObject() + }, + methods: { + adapterHasKey (key) { + const descriptions = this.$store.state.adminSettings.descriptions + const mailerStuff = descriptions[':pleroma']['Pleroma.Emails.Mailer'] + const adapterStuff = mailerStuff[':subgroup,' + this.adapter] + return Object.prototype.hasOwnProperty.call(adapterStuff, key) + } + } +} + +export default MailerTab diff --git a/src/components/settings_modal/admin_tabs/mailer_tab.vue b/src/components/settings_modal/admin_tabs/mailer_tab.vue new file mode 100644 index 000000000..3830a51f9 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/mailer_tab.vue @@ -0,0 +1,150 @@ + + + + {{ $t('admin_dash.mailer.adapter') }} + + + + + + + + {{ $t('admin_dash.mailer.auth') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/media_proxy_tab.js b/src/components/settings_modal/admin_tabs/media_proxy_tab.js new file mode 100644 index 000000000..af82593bc --- /dev/null +++ b/src/components/settings_modal/admin_tabs/media_proxy_tab.js @@ -0,0 +1,38 @@ +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 GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' + +const MediaProxyTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting, + AttachmentSetting, + GroupSetting, + ListSetting + }, + computed: { + mediaProxyEnabled () { + return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':enabled'] + }, + mediaInvalidationProvider () { + return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':invalidation'][':provider'] + }, + ...SharedComputedObject() + } +} + +export default MediaProxyTab diff --git a/src/components/settings_modal/admin_tabs/media_proxy_tab.vue b/src/components/settings_modal/admin_tabs/media_proxy_tab.vue new file mode 100644 index 000000000..3aa22d56f --- /dev/null +++ b/src/components/settings_modal/admin_tabs/media_proxy_tab.vue @@ -0,0 +1,135 @@ + + + + {{ $t('admin_dash.media_proxy.basic') }} + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.media_proxy.invalidation') }} + + + + + + + + {{ $t('admin_dash.media_proxy.invalidation_settings') }} + + + + + + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.media_proxy.limits') }} + + + + + + + + + + + + + {{ $t('admin_dash.media_proxy.thumbnails') }} + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/monitoring_tab.js b/src/components/settings_modal/admin_tabs/monitoring_tab.js new file mode 100644 index 000000000..8593b9d69 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/monitoring_tab.js @@ -0,0 +1,42 @@ +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 GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_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 MonitoringTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting, + AttachmentSetting, + GroupSetting, + ListSetting + }, + computed: { + ...SharedComputedObject() + }, + methods: { + } +} + +export default MonitoringTab diff --git a/src/components/settings_modal/admin_tabs/monitoring_tab.vue b/src/components/settings_modal/admin_tabs/monitoring_tab.vue new file mode 100644 index 000000000..3a58b5795 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/monitoring_tab.vue @@ -0,0 +1,47 @@ + + + + {{ $t('admin_dash.monitoring.builtins') }} + + + + + + + + + {{ $t('admin_dash.monitoring.prometheus') }} + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/other_tab.js b/src/components/settings_modal/admin_tabs/other_tab.js new file mode 100644 index 000000000..dc6550d27 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/other_tab.js @@ -0,0 +1,38 @@ +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 ColorSetting from '../helpers/color_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' +import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue' +import MapSetting from '../helpers/map_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' + +const OtherTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting, + ColorSetting, + AttachmentSetting, + ListSetting, + PWAManifestIconsSetting, + MapSetting, + GroupSetting + }, + computed: { + ...SharedComputedObject() + } +} + +export default OtherTab diff --git a/src/components/settings_modal/admin_tabs/other_tab.vue b/src/components/settings_modal/admin_tabs/other_tab.vue new file mode 100644 index 000000000..967b4bd61 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/other_tab.vue @@ -0,0 +1,134 @@ + + + + {{ $t('admin_dash.other.uncategorized') }} + + + + + + + + + + + + + + + {{ $t('admin_dash.other.reports') }} + + + + + + {{ $t('admin_dash.other.user_backup') }} + + + + + + + + + + + + + + + + {{ $t('admin_dash.other.feed') }} + + {{ $t('admin_dash.other.feed_title') }} + + + + + + + + + + + {{ $t('admin_dash.other.remote_ip') }} + {{ $t('admin_dash.other.remote_ip_description') }} + + + + + + + + + + + + + + + {{ $t('admin_dash.other.mime') }} + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.other.streamer') }} + + + + + + + + + {{ $t('admin_dash.other.privileges') }} + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/posts_tab.js b/src/components/settings_modal/admin_tabs/posts_tab.js new file mode 100644 index 000000000..d9f213594 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/posts_tab.js @@ -0,0 +1,38 @@ +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 ColorSetting from '../helpers/color_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' +import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue' +import MapSetting from '../helpers/map_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' + +const PostsTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting, + ColorSetting, + AttachmentSetting, + ListSetting, + PWAManifestIconsSetting, + MapSetting, + GroupSetting + }, + computed: { + ...SharedComputedObject() + } +} + +export default PostsTab diff --git a/src/components/settings_modal/admin_tabs/posts_tab.vue b/src/components/settings_modal/admin_tabs/posts_tab.vue new file mode 100644 index 000000000..8f2319840 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/posts_tab.vue @@ -0,0 +1,43 @@ + + + + {{ $t('admin_dash.posts.global') }} + + + + + + {{ $t('admin_dash.posts.local') }} + + + + + + {{ $t('admin_dash.posts.scheduled_activites') }} + + + + + + + + + + + + + + {{ $t('admin_dash.posts.remote') }} + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/registrations_tab.js b/src/components/settings_modal/admin_tabs/registrations_tab.js new file mode 100644 index 000000000..3ce6c8044 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/registrations_tab.js @@ -0,0 +1,34 @@ +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 TupleSetting from '../helpers/tuple_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' + +const RegistrationsTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting, + TupleSetting, + AttachmentSetting, + GroupSetting, + ListSetting + }, + computed: { + ...SharedComputedObject() + } +} + +export default RegistrationsTab diff --git a/src/components/settings_modal/admin_tabs/registrations_tab.vue b/src/components/settings_modal/admin_tabs/registrations_tab.vue new file mode 100644 index 000000000..80b16cc69 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/registrations_tab.vue @@ -0,0 +1,188 @@ + + + + {{ $t('admin_dash.instance.registrations') }} + + + + + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.instance.captcha_header') }} + + + + + + + + + + {{ $t('admin_dash.instance.kocaptcha') }} + + + + + + + + + + + + {{ $t('admin_dash.registrations.autofollow') }} + + + + + + + + + {{ $t('admin_dash.registrations.welcome.title') }} + + {{ $t('admin_dash.registrations.welcome.description') }} + + {{ $t('admin_dash.registrations.welcome.direct_message') }} + + + + + + + + + + + + + + + + + {{ $t('admin_dash.registrations.welcome.chat_message') }} + + + + + + + + + + + + + + + + + {{ $t('admin_dash.registrations.welcome.email_message') }} + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.registrations.restrictions') }} + + + + + + + + + + + + + diff --git a/src/components/settings_modal/admin_tabs/uploads_tab.js b/src/components/settings_modal/admin_tabs/uploads_tab.js new file mode 100644 index 000000000..40a184db1 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/uploads_tab.js @@ -0,0 +1,46 @@ +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' + +const UploadsTab = { + provide () { + return { + defaultDraftMode: true, + defaultSource: 'admin' + } + }, + data () { + return { + uploaders: [{ + key: 'Pleroma.Uploaders.Local', + value: 'Pleroma.Uploaders.Local', + label: this.$t('admin_dash.uploads.local_uploader') + }, { + key: 'Pleroma.Uploaders.IPFS', + value: 'Pleroma.Uploaders.IPFS', + label: 'IPFS' + }, { + key: 'Pleroma.Uploaders.S3', + value: 'Pleroma.Uploaders.S3', + label: 'S3' + }] + } + }, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting + }, + computed: { + uploader () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Upload'][':uploader'] + }, + ...SharedComputedObject() + } +} + +export default UploadsTab diff --git a/src/components/settings_modal/admin_tabs/uploads_tab.vue b/src/components/settings_modal/admin_tabs/uploads_tab.vue new file mode 100644 index 000000000..74cbe7ce7 --- /dev/null +++ b/src/components/settings_modal/admin_tabs/uploads_tab.vue @@ -0,0 +1,110 @@ + + + + {{ $t('admin_dash.uploads.upload') }} + + + + {{ $t('admin_dash.uploads.uploader_settings') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ $t('admin_dash.uploads.attachments') }} + + + + + + + + + + {{ $t('admin_dash.uploads.filenames') }} + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/helpers/boolean_setting.vue b/src/components/settings_modal/helpers/boolean_setting.vue index 391318955..5165535cc 100644 --- a/src/components/settings_modal/helpers/boolean_setting.vue +++ b/src/components/settings_modal/helpers/boolean_setting.vue @@ -22,6 +22,7 @@ + {{ ' ' }} ({ key: x, value: x, diff --git a/src/components/settings_modal/helpers/choice_setting.vue b/src/components/settings_modal/helpers/choice_setting.vue index 0e22eb306..a114cc473 100644 --- a/src/components/settings_modal/helpers/choice_setting.vue +++ b/src/components/settings_modal/helpers/choice_setting.vue @@ -2,6 +2,7 @@ {{ backendDescriptionLabel }} @@ -11,8 +12,8 @@ {{ ' ' }} + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + {{ ' ' }} + + {{ ' ' }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + + + diff --git a/src/components/settings_modal/helpers/draft_buttons.vue b/src/components/settings_modal/helpers/draft_buttons.vue index 46a70e866..5d80928e8 100644 --- a/src/components/settings_modal/helpers/draft_buttons.vue +++ b/src/components/settings_modal/helpers/draft_buttons.vue @@ -2,6 +2,7 @@ 0 + const hasBuiltins = this.builtinEntries.length > 0 + + if (hasBuiltins) { + return isExpert + } else { + return true + } + }, + valueSet () { + return new Set(this.visibleState) + }, + suggestionsSet () { + const suggestions = this.backendDescriptionSuggestions + if (suggestions) { + return new Set(suggestions) + } else { + return new Set() + } + }, + extraEntries () { + if (this.ignoreSuggestions) return [...this.valueSet.values()] + if (!this.suggestionsSet) return [] + return [...this.valueSet.values()].filter((x) => { + return !this.builtinEntriesValueSet.has(x) + }) + }, + builtinEntries () { + if (this.ignoreSuggestions) return [] + if (this.overrideAvailableOptions) { + return [...this.options] + } + if (!this.suggestionsSet) return [] + + const builtins = [...this.suggestionsSet.values()] + return builtins.map((option) => ({ + label: option, + value: option + })) + }, + builtinEntriesValueSet () { + return new Set(this.builtinEntries.map(x => x.value)) + } + }, + methods: { + ...Setting.methods, + optionPresent (option) { + return this.valueSet.has(option) + }, + getValue ({ event, value, index, eventType }) { + switch (eventType) { + case 'toggle': { + this.newValue = '' + const newSet = new Set(this.valueSet.values()) + if (event) { + newSet.add(value) + } else { + newSet.delete(value) + } + return [...newSet.values()] + } + + case 'add': { + if (!this.newValue) return this.valueSet.values() + const res = [...this.valueSet.values(), this.newValue] + this.newValue = '' + return res + } + + case 'remove': { + const pre = [...this.valueSet.values()].slice(0, index) + const post = [...this.valueSet.values()].slice(index + 1) + + return [...pre, ...post] + } + + case 'edit': { + const pre = [...this.valueSet.values()].slice(0, index) + const post = [...this.valueSet.values()].slice(index + 1) + const string = event.target.value + if (!string) return [...this.valueSet.values()] + + return [...pre, string, ...post] + } + } + } + } +} diff --git a/src/components/settings_modal/helpers/list_setting.vue b/src/components/settings_modal/helpers/list_setting.vue new file mode 100644 index 000000000..66581fc56 --- /dev/null +++ b/src/components/settings_modal/helpers/list_setting.vue @@ -0,0 +1,90 @@ + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + update({ event, value: item.value, eventType: 'toggle' })" + > + {{ item.label }} + + + + + update({ event: e, index, eventType: 'edit' })" + > + update({ index, eventType: 'remove' })" + > + + + + + + + + update({ eventType: 'add' })" + > + + + + + + + + + + + + + diff --git a/src/components/settings_modal/helpers/list_tuple_setting.js b/src/components/settings_modal/helpers/list_tuple_setting.js new file mode 100644 index 000000000..2cbd93788 --- /dev/null +++ b/src/components/settings_modal/helpers/list_tuple_setting.js @@ -0,0 +1,44 @@ +import ListSetting from './list_setting.js' + +export default { + ...ListSetting, + data () { + return { + newValue: ['',''] + } + }, + methods: { + ...ListSetting.methods, + getValue ({ event, index, eventType, tuple }) { + switch (eventType) { + case 'add': { + if (!this.newValue[0] || !this.newValue[1]) return this.visibleState + const res = [...this.visibleState, this.newValue] + this.newValue = ['', ''] + return res + } + + case 'remove': { + const pre = this.visibleState.slice(0, index) + const post = this.visibleState.slice(index + 1) + + return [...pre, ...post] + } + + case 'edit': { + const pre = this.visibleState.slice(0, index) + const post = this.visibleState.slice(index + 1) + const item = this.visibleState[index] + const string = event.target.value + if (!string) return this.visibleState + + if (tuple === 0) { + return [...pre, [string, item[1]], ...post] + } else { + return [...pre, [item[0], string], ...post] + } + } + } + } + } +} diff --git a/src/components/settings_modal/helpers/list_tuple_setting.vue b/src/components/settings_modal/helpers/list_tuple_setting.vue new file mode 100644 index 000000000..eb2f6e16e --- /dev/null +++ b/src/components/settings_modal/helpers/list_tuple_setting.vue @@ -0,0 +1,113 @@ + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + + update({ event: e, index, eventType: 'edit', tuple: 0 })" + > + update({ event: e, index, eventType: 'edit', tuple: 1 })" + > + update({ index, eventType: 'remove' })" + > + + + + + + + + + update({ eventType: 'add' })" + > + + + + + + + + + + + + + diff --git a/src/components/settings_modal/helpers/map_setting.js b/src/components/settings_modal/helpers/map_setting.js new file mode 100644 index 000000000..ad93ceacf --- /dev/null +++ b/src/components/settings_modal/helpers/map_setting.js @@ -0,0 +1,70 @@ +import Setting from './setting.js' + +export default { + ...Setting, + props: { + ...Setting.props, + allowNew: { + required: false, + type: Boolean, + default: true + } + }, + data () { + return { + newValue: ['',''] // avoiding extra complexity by just using an array instead of an object + } + }, + computed: { + ...Setting.computed, + // state that we'll show in the UI, i.e. transforming map into list + displayState () { + return Object.entries(this.visibleState) + } + }, + methods: { + ...Setting.methods, + getValue ({ event, key, eventType, isKey }) { + switch (eventType) { + case 'add': { + if (key === '') return this.visibleState + const res = {...this.visibleState, ...Object.fromEntries([this.newValue])} + this.newValue = ['', ''] + return res + } + + case 'remove': { + // initial state for this type is empty array + if (Array.isArray(this.visibleState)) return this.visibleState + const newEntries = Object.entries(this.visibleState).filter(([k]) => k !== key) + + if (newEntries.length === 0 ) return [] + return Object.fromEntries(newEntries) + } + + case 'edit': { + const string = event.target.value + const newEntries = Object + .entries(this.visibleState) + .map(([k, v]) => { + if (isKey) { + if (k === key) { + return [string, v] + } else { + return [k, v] + } + } else { + if (k === key) { + return [k, string] + } else { + return [k, v] + } + } + }) + + return Object.fromEntries(newEntries) + } + } + } + } +} diff --git a/src/components/settings_modal/helpers/map_setting.vue b/src/components/settings_modal/helpers/map_setting.vue new file mode 100644 index 000000000..907c0b354 --- /dev/null +++ b/src/components/settings_modal/helpers/map_setting.vue @@ -0,0 +1,112 @@ + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + + update({ event: e, key: item[0], eventType: 'edit', isKey: true })" + > + update({ event: e, key: item[0], eventType: 'edit', isKey: false })" + > + update({ key: item[0], eventType: 'remove' })" + > + + + + + + + + + update({ eventType: 'add' })" + > + + + + + + + + + + + + + diff --git a/src/components/settings_modal/helpers/number_setting.vue b/src/components/settings_modal/helpers/number_setting.vue index 32dc6f83f..e86b3fb08 100644 --- a/src/components/settings_modal/helpers/number_setting.vue +++ b/src/components/settings_modal/helpers/number_setting.vue @@ -4,7 +4,9 @@ class="NumberSetting" > @@ -22,6 +24,7 @@ type="number" :step="step || 1" :disabled="shouldBeDisabled" + :placeholder="backendDescriptionSuggestions" :min="min || 0" :value="realDraftMode ? draft :state" @change="update" @@ -32,7 +35,7 @@ :onclick="reset" /> - + state?.tuple ? state.tuple[1] + ':' + state.tuple[2] : state +const getSocks = state => state?.tuple + +export default { + ...Setting, + data () { + return { + urlField: '', + socksField: false + } + }, + created () { + Setting.created() + this.urlField = getUrl(this.realDraftMode ? this.draft : this.state) + this.socksField = getSocks(this.realDraftMode ? this.draft : this.state) + }, + computed: { + ...Setting.computed, + // state that we'll show in the UI, i.e. transforming map into list + displayState () { + if (this.visibleState?.tuple) { + return this.visibleState.tuple[1] + ':' + this.visibleState.tuple[2] + } + return this.visibleState + }, + socksState () { + return getSocks(this.visibleState) + } + }, + components: { + ...Setting.components, + Checkbox + }, + methods: { + ...Setting.methods, + getValue ({ event, isProxy}) { + if (isProxy) { + this.socksField = event + } else { + this.urlField = event.target.value + } + + if (this.socksField) { + return { tuple: [ ':socks5', ...this.urlField.split(':') ] } + } else { + return this.urlField + } + } + } +} diff --git a/src/components/settings_modal/helpers/proxy_setting.vue b/src/components/settings_modal/helpers/proxy_setting.vue new file mode 100644 index 000000000..ac4884696 --- /dev/null +++ b/src/components/settings_modal/helpers/proxy_setting.vue @@ -0,0 +1,57 @@ + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + {{ ' ' }} + update({ event })" + > + {{ ' ' }} + update({ event, isProxy: true})" + > + {{ $t('admin_dash.http.socks5') }} + {{ ' ' }} + + {{ ' ' }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + + diff --git a/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js new file mode 100644 index 000000000..3e6ff23fa --- /dev/null +++ b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js @@ -0,0 +1,45 @@ +import { clone } from 'lodash' +import Setting from './setting.js' + +export default { + ...Setting, + methods: { + ...Setting.methods, + optionPresent (option) { + return this.valueSet.has(option) + }, + getValue ({ event, field, index, eventType }) { + switch (eventType) { + case 'add': { + const res = [...this.visibleState, {}] + return res + } + + case 'remove': { + const pre = this.visibleState.slice(0, index) + const post = this.visibleState.slice(index + 1) + + return [...pre, ...post] + } + + case 'edit': { + const pre = this.visibleState.slice(0, index) + const post = this.visibleState.slice(index + 1) + const item = clone(this.visibleState[index]) + const string = event.target.value + console.log(item) + + if (!string) { + delete item[field] + } else { + item[field] = string + } + + console.log(item) + + return [...pre, item, ...post] + } + } + } + } +} diff --git a/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue new file mode 100644 index 000000000..ab43a2c1a --- /dev/null +++ b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue @@ -0,0 +1,138 @@ + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + + + purpose + + update({ event: e, index, eventType: 'edit', field: ':purpose' })" + > + + sizes + + update({ event: e, index, eventType: 'edit', field: ':sizes' })" + > + + src + + update({ event: e, index, eventType: 'edit', field: ':src' })" + > + + type + + update({ event: e, index, eventType: 'edit', field: ':type' })" + > + + + + update({ eventType: 'add' })" + > + + + update({ index, eventType: 'remove' })" + > + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js index df137157a..f786a35da 100644 --- a/src/components/settings_modal/helpers/setting.js +++ b/src/components/settings_modal/helpers/setting.js @@ -1,7 +1,7 @@ import ModifiedIndicator from './modified_indicator.vue' import ProfileSettingIndicator from './profile_setting_indicator.vue' import DraftButtons from './draft_buttons.vue' -import { get, set, cloneDeep } from 'lodash' +import { get, set, cloneDeep, isEqual } from 'lodash' export default { components: { @@ -18,6 +18,18 @@ export default { type: [String, Array], required: false }, + descriptionPathOverride: { + type: [String, Array], + required: false + }, + suggestions: { + type: [String, Array], + required: false + }, + subgroup: { + type: String, + required: false + }, disabled: { type: Boolean, default: false @@ -37,12 +49,22 @@ export default { type: String, default: undefined }, + hideDraftButtons: { // this is for the weird backend hybrid (Boolean|String or Boolean|Number) settings + required: false, + type: Boolean + }, + hideLabel: { + type: Boolean + }, hideDescription: { type: Boolean }, swapDescriptionAndLabel: { type: Boolean }, + backendDescriptionPath: { + type: [String, Array] + }, overrideBackendDescription: { type: Boolean }, @@ -73,7 +95,7 @@ export default { }, created () { if (this.realDraftMode && (this.realSource !== 'admin' || this.path == null)) { - this.draft = this.state + this.draft = cloneDeep(this.state) } }, computed: { @@ -114,10 +136,13 @@ export default { return typeof this.draftMode === 'undefined' ? this.defaultDraftMode : this.draftMode }, backendDescription () { - return get(this.$store.state.adminSettings.descriptions, this.path) + return get(this.$store.state.adminSettings.descriptions, this.descriptionPath) }, backendDescriptionLabel () { if (this.realSource !== 'admin') return '' + if (this.overrideBackendDescriptionLabel !== '' && typeof this.overrideBackendDescriptionLabel === 'string') { + return this.overrideBackendDescriptionLabel + } if (!this.backendDescription || this.overrideBackendDescriptionLabel) { return this.$t([ 'admin_dash', @@ -148,13 +173,20 @@ export default { } }, backendDescriptionSuggestions () { - return this.backendDescription?.suggestions + return this.backendDescription?.suggestions || this.suggestions }, shouldBeDisabled () { if (this.path == null) { return this.disabled } - const parentValue = this.parentPath !== undefined ? get(this.configSource, this.parentPath) : null + let parentValue = null + if (this.parentPath !== undefined && this.realSource === 'admin') { + if (this.realDraftMode) { + parentValue = get(this.$store.state.adminSettings.draft, this.parentPath) + } else { + parentValue = get(this.configSource, this.parentPath) + } + } return this.disabled || (parentValue !== null ? (this.parentInvert ? parentValue : !parentValue) : false) }, configSource () { @@ -209,17 +241,29 @@ export default { if (this.path == null) return null return Array.isArray(this.path) ? this.path : this.path.split('.') }, + descriptionPath () { + if (this.path == null) return null + if (this.descriptionPathOverride) return this.descriptionPathOverride + const path = Array.isArray(this.path) ? this.path : this.path.split('.') + if (this.subgroup) { + return [ + ...path.slice(0, path.length - 1), + ':subgroup,' + this.subgroup, + ...path.slice(path.length - 1) + ] + } + return path + }, isDirty () { 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 && this.draft !== this.state + return this.realDraftMode && !isEqual(this.draft, this.state) } }, canHardReset () { - return this.realSource === 'admin' && this.$store.state.adminSettings.modifiedPaths && - this.$store.state.adminSettings.modifiedPaths.has(this.canonPath.join(' -> ')) + return this.realSource === 'admin' && this.$store.state.adminSettings.modifiedPaths?.has(this.canonPath.join(' -> ')) }, matchesExpertLevel () { return (this.expert || 0) <= this.$store.state.config.expertLevel > 0 diff --git a/src/components/settings_modal/helpers/string_setting.vue b/src/components/settings_modal/helpers/string_setting.vue index d0c70b150..8fba8b499 100644 --- a/src/components/settings_modal/helpers/string_setting.vue +++ b/src/components/settings_modal/helpers/string_setting.vue @@ -4,6 +4,7 @@ class="StringSetting" > @@ -30,7 +33,7 @@ :onclick="reset" /> - + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + {{ ' ' }} + update({ e, side: 0 })" + > + {{ ' ' }} + update({ e, side: 1 })" + > + {{ ' ' }} + update({ e, side: 2 })" + > + {{ ' ' }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + + diff --git a/src/components/settings_modal/helpers/vertical_tab_switcher.jsx b/src/components/settings_modal/helpers/vertical_tab_switcher.jsx index 7fea1cab8..bbb36af6f 100644 --- a/src/components/settings_modal/helpers/vertical_tab_switcher.jsx +++ b/src/components/settings_modal/helpers/vertical_tab_switcher.jsx @@ -159,10 +159,10 @@ export default { const wrapperClasses = ['tab-content-wrapper', active ? '-active' : '-hidden' ] const contentClasses = ['tab-content'] - if (props['full-width']) { + if (props['full-width'] || props['full-width'] === '') { contentClasses.push('-full-width') } - if (props['full-height']) { + if (props['full-height'] || props['full-width'] === '') { contentClasses.push('-full-height') } return ( diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss index fd24697b6..9e04c3fe7 100644 --- a/src/components/settings_modal/settings_modal.scss +++ b/src/components/settings_modal/settings_modal.scss @@ -31,6 +31,14 @@ margin-top: 0; } + p { + line-height: 1.5; + } + + .setting-item > p { + margin-left: 1em; + } + .setting-list, .option-list { list-style-type: none; @@ -41,8 +49,21 @@ padding: 0 2em; } + .btn-group { + .button-default { + flex: 0 1 auto; + } + } + li { - margin: 1em 0; + display: block; + margin: 0.75em 0; + + > label { + display: block; + margin: 0.75em 0; + padding: 0.5em 0; + } } .suboptions { @@ -62,8 +83,8 @@ .setting-description { margin-top: 0.2em; - margin-bottom: 2em; - font-size: 70%; + margin-bottom: 0; + font-size: 80%; } .settings-modal-panel { diff --git a/src/components/settings_modal/settings_modal_admin_content.js b/src/components/settings_modal/settings_modal_admin_content.js index bc0039118..4a05868d8 100644 --- a/src/components/settings_modal/settings_modal_admin_content.js +++ b/src/components/settings_modal/settings_modal_admin_content.js @@ -1,32 +1,58 @@ import VerticalTabSwitcher from './helpers/vertical_tab_switcher.jsx' import InstanceTab from './admin_tabs/instance_tab.vue' +import LinksTab from './admin_tabs/links_tab.vue' import LimitsTab from './admin_tabs/limits_tab.vue' import FrontendsTab from './admin_tabs/frontends_tab.vue' +import MediaProxyTab from './admin_tabs/media_proxy_tab.vue' import EmojiTab from './admin_tabs/emoji_tab.vue' +import UploadsTab from './admin_tabs/uploads_tab.vue' +import MailerTab from './admin_tabs/mailer_tab.vue' +import MonitoringTab from './admin_tabs/monitoring_tab.vue' +import RegistrationsTab from './admin_tabs/registrations_tab.vue' +import AuthTab from './admin_tabs/auth_tab.vue' +import HTTPTab from './admin_tabs/http_tab.vue' +import OtherTab from './admin_tabs/other_tab.vue' +import PostsTab from './admin_tabs/posts_tab.vue' +import FederationTab from './admin_tabs/federation_tab.vue' +import JobQueuesTab from './admin_tabs/job_queues_tab.vue' import { useInterfaceStore } from 'src/stores/interface' import { library } from '@fortawesome/fontawesome-svg-core' import { faWrench, faHand, + faChain, + faGlobe, faLaptopCode, - faPaintBrush, - faBell, - faDownload, - faEyeSlash, - faInfo + faTowerBroadcast, + faEnvelope, + faChartLine, + faDoorOpen, + faGears, + faKey, + faCircleNodes, + faUpload, + faMessage, + faEllipsis } from '@fortawesome/free-solid-svg-icons' library.add( faWrench, faHand, + faChain, + faGlobe, faLaptopCode, - faPaintBrush, - faBell, - faDownload, - faEyeSlash, - faInfo + faTowerBroadcast, + faEnvelope, + faChartLine, + faDoorOpen, + faGears, + faKey, + faCircleNodes, + faUpload, + faMessage, + faEllipsis ) const SettingsModalAdminContent = { @@ -34,9 +60,21 @@ const SettingsModalAdminContent = { VerticalTabSwitcher, InstanceTab, - LimitsTab, + RegistrationsTab, + EmojiTab, FrontendsTab, - EmojiTab + FederationTab, + LimitsTab, + MailerTab, + UploadsTab, + MediaProxyTab, + LinksTab, + JobQueuesTab, + AuthTab, + HTTPTab, + MonitoringTab, + OtherTab, + PostsTab }, computed: { user () { diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue index 501a3acf6..80c82d84f 100644 --- a/src/components/settings_modal/settings_modal_admin_content.vue +++ b/src/components/settings_modal/settings_modal_admin_content.vue @@ -48,6 +48,41 @@ > + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/tabs/appearance_tab.vue b/src/components/settings_modal/tabs/appearance_tab.vue index d9303ce7b..815a6d4c5 100644 --- a/src/components/settings_modal/tabs/appearance_tab.vue +++ b/src/components/settings_modal/tabs/appearance_tab.vue @@ -161,13 +161,16 @@ - - - + + + { - console.log(id) delete this.muteFiltersDraftObject[id] this.unsetPreference({ path: 'simple.muteFilters.' + id , value: null }) }) diff --git a/src/components/settings_modal/tabs/uploads_tab.vue b/src/components/settings_modal/tabs/uploads_tab.vue new file mode 100644 index 000000000..b11dc1381 --- /dev/null +++ b/src/components/settings_modal/tabs/uploads_tab.vue @@ -0,0 +1,26 @@ + + + + {{ $t('admin_dash.uploads.general') }} + + + + + {{ $t('admin_dash.mailer.auth') }} + + + + + + + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index e1f5fb23d..6be3e8b74 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -1152,7 +1152,80 @@ "instance": "Instance", "limits": "Limits", "frontends": "Front-ends", - "emoji": "Emoji" + "mailer": "EMails", + "media_proxy": "Media Proxy", + "emoji": "Emoji", + "uploads": "Uploads", + "monitoring": "Monitoring", + "registrations": "Registrations", + "links": "Links", + "job_queues": "Job Queues", + "auth": "Auth", + "posts": "Posts", + "http": "HTTP", + "federation": "Federation", + "other": "Other" + }, + "posts": { + "global": "Global settings", + "local": "Local posts", + "scheduled_activites": "Scheduled posts", + "remote": "Remote posts" + }, + "other": { + "uncategorized": "Uncategorized", + "user_backup": "User Backup", + "reports": "Reports", + "feed": "RSS Feed", + "feed_title": "Article Title", + "mime": "MIME Types", + "remote_ip": "Reverse Proxy / Remote IP", + "remote_ip_description": "This should be disabled only if your instance is NOT behind a reverse proxy", + "streamer": "Notifications Streamer", + "privileges": "Privileges" + }, + "monitoring": { + "builtins": "Built-in Tools", + "prometheus": "Prometheus Exporter" + }, + "federation": { + "global": "Global settings", + "restrictions": "Restrictions", + "activitypub": "ActivityPub" + }, + "http": { + "outbound": "Outbound HTTP requests", + "socks5": "SOCKS5" + }, + "auth": { + "MFA": "Multi-factor Authentication", + "LDAP": "LDAP Settings", + "OAuth": "Oauth2 settings", + "TOTP": "One-time Passwords (TOTP)", + "backup_codes": "Backup codes" + }, + "job_queues": { + "Oban": "Oban queues", + "Gun": { + "title": "Gun queues", + "connections_pools": "Gun connections pool", + "pools": { + "title": "Gun worker pools", + "default": "Default pool", + "federation": "Federation pool", + "media": "Media pool", + "rich_media": "Rich media pool", + "upload": "Upload pool" + } + }, + "Hackney": { + "title": "Hackney pools", + "federation": "Federation", + "media": "Media", + "rich_media": "Rich media", + "upload": "Upload" + }, + "queues": "Queues" }, "nodb": { "heading": "Database config is disabled", @@ -1164,29 +1237,79 @@ "native": "Native", "kocaptcha": "KoCaptcha" }, + "http": { + "outbound": "Outgoing connections", + "incoming": "Incoming connections", + "security": "HTTP Security", + "cors": "Cross-origin Resource Sharing (CORS)", + "web_cache_ttl": "Web Cache TTL", + "web_cache_ttl_description": "Amount of milliseconds until web response cache is cleared. Use `nil` to disable expiration entirely.", + "web_push": "Web Push", + "web_push_description": "Web Push VAPID settings. You can use the mix task web_push.gen.keypair to generate it." + }, "instance": { "instance": "Instance information", + "branding": "Branding", "registrations": "User sign-ups", "captcha_header": "CAPTCHA", "kocaptcha": "KoCaptcha settings", "access": "Instance access", + "rich_metadata": "Metadata", "restrict": { "header": "Restrict access for anonymous visitors", "description": "Detailed setting for allowing/disallowing access to certain aspects of API. By default (indeterminate state) it will disallow if instance is not public, ticked checkbox means disallow access even if instance is public, unticked means allow access even if instance is private. Please note that unexpected behavior might happen if some settings are set, i.e. if profile access is disabled posts will show without profile information.", "timelines": "Timelines access", "profiles": "User profiles access", "activities": "Statuses/activities access" - } + }, + ":unauthenticated": "Unauthenticated", + ":all": "Everyone" + }, + "registrations": { + "welcome": { + "title": "Welcome message", + "description": "Send new users a message when they sign up", + "direct_message": "Via direct message", + "chat_message": "Via chat", + "email_message": "Via email" + }, + "restrictions": "Restrictions", + "autofollow": "Autofollow" + }, + "links": { + "no_scheme": "No scheme", + "link_previews": "Link previews", + "link_formatter": "Link formatter" + }, + "uploads": { + "attachments": "Attachments settings", + "upload": "Upload", + "local_uploader": "Local files", + "filenames": "Filenames, Titles and Descriptions", + "uploader_settings": "Uploader settings" + }, + "media_proxy": { + "basic": "Basic Settings", + "invalidation": "Cache Invalidation", + "limits": "Limits", + "thumbnails": "Thumbnail Generation", + "invalidation_settings": "Cache Invalidation" + }, + "mailer": { + "adapter": "Mailing Adapter", + "auth": "Authentication" }, "limits": { "arbitrary_limits": "Arbitrary limits", "posts": "Post limits", + "other": "Misc. limits", "uploads": "Attachments limits", "users": "User profile limits", "profile_fields": "Profile fields limits", "user_uploads": "Profile media limits" }, "frontend": { + "title": "Frontend management", "repository": "Repository link", "versions": "Available versions", "build_url": "Build URL", @@ -1210,7 +1333,11 @@ "emoji": { "global_actions": "Global actions", "reload": "Reload emoji", + "reload_short": "Refresh", + "advanced": "Advanced", "importFS": "Import emoji from filesystem", + "import_pack": "Upload emoji pack", + "import_pack_short": "Import", "error": "Error: {0}", "create_pack": "Create pack", "delete_pack": "Delete pack", @@ -1218,10 +1345,12 @@ "create": "Create", "emoji_packs": "Emoji packs", "remote_packs": "Remote packs", + "remote_packs_short": "Remote", "do_list": "List", "remote_pack_instance": "Remote pack instance", "emoji_pack": "Emoji pack", "edit_pack": "Edit pack", + "metadata": "Metadata", "description": "Description", "homepage": "Homepage", "fallback_src": "Fallback source", @@ -1257,8 +1386,67 @@ "replace_warning": "This will REPLACE the local pack of the same name", "copied_successfully": "Successfully copied emoji \"{0}\" to pack \"{1}\"" }, + "generic_enforcement": { + "if_available": "If available", + "always": "Always", + "never": "Never" + }, "temp_overrides": { ":pleroma": { + "Oban": { + ":queues": { + ":scheduled_activites": { + "label": "Scheduled activities", + "description": "Scheduled activites queue" + }, + ":slow": { + "label": "Slow", + "description": "idk" + } + } + }, + ":connections_pool": { + ":max_idle_time": { + "label": "Maximum idle time", + "description": "idk" + }, + ":retry": { + "label": "Retry", + "description": "idk" + } + }, + ":pools": { + ":rich_media": { + "label": "Rich media", + "description": "idk" + } + }, + "Pleroma_DOT_Formatter": { + ":attribute_toggle": { + "label": "Set {attr} attribute" + }, + ":truncate_toggle": { + "label": "Truncate" + }, + ":class": { + "label": "Value" + }, + ":rel": { + "label": "Value" + } + }, + "Pleroma_DOT_Uploaders_DOT_Uploader": { + ":timeout": { + "label": "Timeout", + "description": "Amount of milliseconds before dropping connection" + } + }, + "Pleroma_DOT_Upload": { + ":default_description": { + "label": "Default description", + "description": "Default description to give to a file. Setting it to ':filename' will use file's filename as description." + } + }, ":instance": { ":public": { "label": "Instance is public", @@ -1276,6 +1464,16 @@ "label": "Background image", "description": "Background image (primarily used by PleromaFE)" } + }, + ":http_security": { + ":allow_unsafe_eval": { + "label": "Allow unsafe-eval", + "description": "Allow unsafe evaluation of scripts (required for Flash support)" + }, + ":report_url": { + "label": "Report URL", + "description": "URL to report security violations to" + } } } } diff --git a/src/modules/adminSettings.js b/src/modules/adminSettings.js index 38fb5305a..bbe4beba6 100644 --- a/src/modules/adminSettings.js +++ b/src/modules/adminSettings.js @@ -105,6 +105,16 @@ const adminSettingsStorage = { } set(config, path, convert(c.value)) }) + console.log('CONFIG', JSON.parse(JSON.stringify(config))) + // patching http adapter config to be easier to handle + const adapter = config[':pleroma'][':http'][':adapter'] + if (Array.isArray(adapter)) { + config[':pleroma'][':http'][':adapter'] = { + [':ssl_options']: { + [':versions']: [] + } + } + } commit('updateAdminSettings', { config, modifiedPaths }) commit('resetAdminDraft') }, @@ -121,7 +131,9 @@ const adminSettingsStorage = { } const descriptions = {} + backendDescriptions.forEach(d => convert(d, '', descriptions)) + console.log('DESCRIPTIONS', descriptions) commit('updateAdminDescriptions', { descriptions }) }, @@ -206,7 +218,7 @@ const adminSettingsStorage = { .then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig })) }, resetAdminSetting ({ rootState, state, dispatch }, { path }) { - const [group, key, subkey] = path.split(/\./g) + const [group, key, subkey] = Array.isArray(path) ? path : path.split(/\./g) state.modifiedPaths.delete(path)
{{ $t('admin_dash.frontend.wip_notice') }}
{{ $t('admin_dash.frontend.default_frontend_tip') }}
{{ $t('admin_dash.http.web_cache_ttl_description') }}
{{ $t('admin_dash.http.web_push_description') }}
class
rel
{{ $t('admin_dash.other.remote_ip_description') }}
{{ $t('admin_dash.registrations.welcome.description') }}
+ {{ backendDescriptionDescription + ' ' }} +
state?.tuple ? state.tuple[1] + ':' + state.tuple[2] : state +const getSocks = state => state?.tuple + +export default { + ...Setting, + data () { + return { + urlField: '', + socksField: false + } + }, + created () { + Setting.created() + this.urlField = getUrl(this.realDraftMode ? this.draft : this.state) + this.socksField = getSocks(this.realDraftMode ? this.draft : this.state) + }, + computed: { + ...Setting.computed, + // state that we'll show in the UI, i.e. transforming map into list + displayState () { + if (this.visibleState?.tuple) { + return this.visibleState.tuple[1] + ':' + this.visibleState.tuple[2] + } + return this.visibleState + }, + socksState () { + return getSocks(this.visibleState) + } + }, + components: { + ...Setting.components, + Checkbox + }, + methods: { + ...Setting.methods, + getValue ({ event, isProxy}) { + if (isProxy) { + this.socksField = event + } else { + this.urlField = event.target.value + } + + if (this.socksField) { + return { tuple: [ ':socks5', ...this.urlField.split(':') ] } + } else { + return this.urlField + } + } + } +} diff --git a/src/components/settings_modal/helpers/proxy_setting.vue b/src/components/settings_modal/helpers/proxy_setting.vue new file mode 100644 index 000000000..ac4884696 --- /dev/null +++ b/src/components/settings_modal/helpers/proxy_setting.vue @@ -0,0 +1,57 @@ + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + {{ ' ' }} + update({ event })" + > + {{ ' ' }} + update({ event, isProxy: true})" + > + {{ $t('admin_dash.http.socks5') }} + {{ ' ' }} + + {{ ' ' }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + + diff --git a/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js new file mode 100644 index 000000000..3e6ff23fa --- /dev/null +++ b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js @@ -0,0 +1,45 @@ +import { clone } from 'lodash' +import Setting from './setting.js' + +export default { + ...Setting, + methods: { + ...Setting.methods, + optionPresent (option) { + return this.valueSet.has(option) + }, + getValue ({ event, field, index, eventType }) { + switch (eventType) { + case 'add': { + const res = [...this.visibleState, {}] + return res + } + + case 'remove': { + const pre = this.visibleState.slice(0, index) + const post = this.visibleState.slice(index + 1) + + return [...pre, ...post] + } + + case 'edit': { + const pre = this.visibleState.slice(0, index) + const post = this.visibleState.slice(index + 1) + const item = clone(this.visibleState[index]) + const string = event.target.value + console.log(item) + + if (!string) { + delete item[field] + } else { + item[field] = string + } + + console.log(item) + + return [...pre, item, ...post] + } + } + } + } +} diff --git a/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue new file mode 100644 index 000000000..ab43a2c1a --- /dev/null +++ b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue @@ -0,0 +1,138 @@ + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + + {{ backendDescriptionDescription + ' ' }} + + + + + + purpose + + update({ event: e, index, eventType: 'edit', field: ':purpose' })" + > + + sizes + + update({ event: e, index, eventType: 'edit', field: ':sizes' })" + > + + src + + update({ event: e, index, eventType: 'edit', field: ':src' })" + > + + type + + update({ event: e, index, eventType: 'edit', field: ':type' })" + > + + + + update({ eventType: 'add' })" + > + + + update({ index, eventType: 'remove' })" + > + + + + + + + + + + + + + + diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js index df137157a..f786a35da 100644 --- a/src/components/settings_modal/helpers/setting.js +++ b/src/components/settings_modal/helpers/setting.js @@ -1,7 +1,7 @@ import ModifiedIndicator from './modified_indicator.vue' import ProfileSettingIndicator from './profile_setting_indicator.vue' import DraftButtons from './draft_buttons.vue' -import { get, set, cloneDeep } from 'lodash' +import { get, set, cloneDeep, isEqual } from 'lodash' export default { components: { @@ -18,6 +18,18 @@ export default { type: [String, Array], required: false }, + descriptionPathOverride: { + type: [String, Array], + required: false + }, + suggestions: { + type: [String, Array], + required: false + }, + subgroup: { + type: String, + required: false + }, disabled: { type: Boolean, default: false @@ -37,12 +49,22 @@ export default { type: String, default: undefined }, + hideDraftButtons: { // this is for the weird backend hybrid (Boolean|String or Boolean|Number) settings + required: false, + type: Boolean + }, + hideLabel: { + type: Boolean + }, hideDescription: { type: Boolean }, swapDescriptionAndLabel: { type: Boolean }, + backendDescriptionPath: { + type: [String, Array] + }, overrideBackendDescription: { type: Boolean }, @@ -73,7 +95,7 @@ export default { }, created () { if (this.realDraftMode && (this.realSource !== 'admin' || this.path == null)) { - this.draft = this.state + this.draft = cloneDeep(this.state) } }, computed: { @@ -114,10 +136,13 @@ export default { return typeof this.draftMode === 'undefined' ? this.defaultDraftMode : this.draftMode }, backendDescription () { - return get(this.$store.state.adminSettings.descriptions, this.path) + return get(this.$store.state.adminSettings.descriptions, this.descriptionPath) }, backendDescriptionLabel () { if (this.realSource !== 'admin') return '' + if (this.overrideBackendDescriptionLabel !== '' && typeof this.overrideBackendDescriptionLabel === 'string') { + return this.overrideBackendDescriptionLabel + } if (!this.backendDescription || this.overrideBackendDescriptionLabel) { return this.$t([ 'admin_dash', @@ -148,13 +173,20 @@ export default { } }, backendDescriptionSuggestions () { - return this.backendDescription?.suggestions + return this.backendDescription?.suggestions || this.suggestions }, shouldBeDisabled () { if (this.path == null) { return this.disabled } - const parentValue = this.parentPath !== undefined ? get(this.configSource, this.parentPath) : null + let parentValue = null + if (this.parentPath !== undefined && this.realSource === 'admin') { + if (this.realDraftMode) { + parentValue = get(this.$store.state.adminSettings.draft, this.parentPath) + } else { + parentValue = get(this.configSource, this.parentPath) + } + } return this.disabled || (parentValue !== null ? (this.parentInvert ? parentValue : !parentValue) : false) }, configSource () { @@ -209,17 +241,29 @@ export default { if (this.path == null) return null return Array.isArray(this.path) ? this.path : this.path.split('.') }, + descriptionPath () { + if (this.path == null) return null + if (this.descriptionPathOverride) return this.descriptionPathOverride + const path = Array.isArray(this.path) ? this.path : this.path.split('.') + if (this.subgroup) { + return [ + ...path.slice(0, path.length - 1), + ':subgroup,' + this.subgroup, + ...path.slice(path.length - 1) + ] + } + return path + }, isDirty () { 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 && this.draft !== this.state + return this.realDraftMode && !isEqual(this.draft, this.state) } }, canHardReset () { - return this.realSource === 'admin' && this.$store.state.adminSettings.modifiedPaths && - this.$store.state.adminSettings.modifiedPaths.has(this.canonPath.join(' -> ')) + return this.realSource === 'admin' && this.$store.state.adminSettings.modifiedPaths?.has(this.canonPath.join(' -> ')) }, matchesExpertLevel () { return (this.expert || 0) <= this.$store.state.config.expertLevel > 0 diff --git a/src/components/settings_modal/helpers/string_setting.vue b/src/components/settings_modal/helpers/string_setting.vue index d0c70b150..8fba8b499 100644 --- a/src/components/settings_modal/helpers/string_setting.vue +++ b/src/components/settings_modal/helpers/string_setting.vue @@ -4,6 +4,7 @@ class="StringSetting" > @@ -30,7 +33,7 @@ :onclick="reset" /> - + + + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + {{ ' ' }} + update({ e, side: 0 })" + > + {{ ' ' }} + update({ e, side: 1 })" + > + {{ ' ' }} + update({ e, side: 2 })" + > + {{ ' ' }} + + + + + {{ backendDescriptionDescription + ' ' }} + + +
purpose
sizes
src
type
+ + + + {{ backendDescriptionLabel + ' ' }} + + + MISSING LABEL FOR {{ path }} + + + + {{ ' ' }} + update({ e, side: 0 })" + > + {{ ' ' }} + update({ e, side: 1 })" + > + {{ ' ' }} + update({ e, side: 2 })" + > + {{ ' ' }} + + + + + {{ backendDescriptionDescription + ' ' }} + + +