From 540ea2f3c0ba0a33cc4ce94ac7721d6ff7da057f Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 9 Apr 2025 00:02:45 +0300 Subject: [PATCH 1/4] fix migrations applying over and over --- src/modules/users.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/users.js b/src/modules/users.js index d5ef6cdf5..01936c716 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -641,7 +641,8 @@ const users = { declarations .filter(x => { return x.store === 'server-side' && - (x.migrationNum ?? x.migrationNum > configMigration) + x.migrationNum > 0 && + x.migrationNum > configMigration }) .toSorted((a, b) => a.configMigration - b.configMigration) .forEach(value => { From 1dc22e267889b3c240f6be7fde50a93cd3b6e591 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 9 Apr 2025 00:03:18 +0300 Subject: [PATCH 2/4] style fixes --- .../settings_modal/tabs/filtering_tab.scss | 15 ++++++++++++++- src/i18n/en.json | 10 ++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/components/settings_modal/tabs/filtering_tab.scss b/src/components/settings_modal/tabs/filtering_tab.scss index 6346654b9..979096126 100644 --- a/src/components/settings_modal/tabs/filtering_tab.scss +++ b/src/components/settings_modal/tabs/filtering_tab.scss @@ -12,7 +12,7 @@ margin: 0.5em; padding: 0.5em; display: grid; - grid-template-columns: fit-content() 1fr fit-content(); + grid-template-columns: fit-content 1fr fit-content; align-items: baseline; grid-gap: 0.5em; } @@ -33,6 +33,7 @@ grid-column: 3; grid-row: 1; text-align: right; + line-height: 2; } .filter-field { @@ -55,5 +56,17 @@ .filter-buttons { grid-column: 1 / span 3; justify-self: end; + display: inline-grid; + grid-gap: 0.5em; + grid-template-columns: repeat(4, 1fr); + max-width: 100%; + justify-content: end; + } +} + + +.settings-modal.-mobile .filtering-tab { + .filter-buttons { + grid-template-columns: repeat(1, 1fr); } } diff --git a/src/i18n/en.json b/src/i18n/en.json index 0ea770c40..3695cb088 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -424,10 +424,12 @@ "value": "Value", "expires": "Expires", "expired": "Expired", - "copy": "Copy filter", - "save": "Save filter", - "delete": "Remove filter", - "new": "Create filter", + "copy": "Duplicate", + "save": "Save", + "delete": "Remove", + "new": "Create new", + "import": "Import", + "export": "Export", "regexp_error": "Invalid Regular Expression", "never_expires": "Never", "help": { From 45e6e03a0315966f6d6a97e6bff08ea46afe2ff9 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 9 Apr 2025 00:31:22 +0300 Subject: [PATCH 3/4] fix global notices not working sometimes --- src/components/settings_modal/admin_tabs/emoji_tab.js | 3 ++- src/components/settings_modal/admin_tabs/frontends_tab.js | 5 +++-- src/components/settings_modal/tabs/appearance_tab.js | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/settings_modal/admin_tabs/emoji_tab.js b/src/components/settings_modal/admin_tabs/emoji_tab.js index 585254a9b..7f575bcb4 100644 --- a/src/components/settings_modal/admin_tabs/emoji_tab.js +++ b/src/components/settings_modal/admin_tabs/emoji_tab.js @@ -8,6 +8,7 @@ import Popover from 'components/popover/popover.vue' import ConfirmModal from 'components/confirm_modal/confirm_modal.vue' import ModifiedIndicator from '../helpers/modified_indicator.vue' import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue' +import { useInterfaceStore } from 'src/stores/interface' const EmojiTab = { components: { @@ -232,7 +233,7 @@ const EmojiTab = { }) }, displayError (msg) { - this.$store.useInterfaceStore().pushGlobalNotice({ + useInterfaceStore().pushGlobalNotice({ messageKey: 'admin_dash.emoji.error', messageArgs: [msg], level: 'error' diff --git a/src/components/settings_modal/admin_tabs/frontends_tab.js b/src/components/settings_modal/admin_tabs/frontends_tab.js index 6d983104b..a9a4777da 100644 --- a/src/components/settings_modal/admin_tabs/frontends_tab.js +++ b/src/components/settings_modal/admin_tabs/frontends_tab.js @@ -5,6 +5,7 @@ import StringSetting from '../helpers/string_setting.vue' import GroupSetting from '../helpers/group_setting.vue' import Popover from 'src/components/popover/popover.vue' import PanelLoading from 'src/components/panel_loading/panel_loading.vue' +import { useInterfaceStore } from 'src/stores/interface' import SharedComputedObject from '../helpers/shared_computed_object.js' import { library } from '@fortawesome/fontawesome-svg-core' @@ -80,7 +81,7 @@ const FrontendsTab = { this.$store.dispatch('loadFrontendsStuff') if (response.error) { const reason = await response.error.json() - this.$store.useInterfaceStore().pushGlobalNotice({ + useInterfaceStore().pushGlobalNotice({ level: 'error', messageKey: 'admin_dash.frontend.failure_installing_frontend', messageArgs: { @@ -90,7 +91,7 @@ const FrontendsTab = { timeout: 5000 }) } else { - this.$store.useInterfaceStore().pushGlobalNotice({ + useInterfaceStore().pushGlobalNotice({ level: 'success', messageKey: 'admin_dash.frontend.success_installing_frontend', messageArgs: { diff --git a/src/components/settings_modal/tabs/appearance_tab.js b/src/components/settings_modal/tabs/appearance_tab.js index da72c8f55..fd18b91e5 100644 --- a/src/components/settings_modal/tabs/appearance_tab.js +++ b/src/components/settings_modal/tabs/appearance_tab.js @@ -315,7 +315,7 @@ const AppearanceTab = { }, onImportFailure (result) { console.error('Failure importing theme:', result) - this.$store.useInterfaceStore().pushGlobalNotice({ messageKey: 'settings.invalid_theme_imported', level: 'error' }) + useInterfaceStore().pushGlobalNotice({ messageKey: 'settings.invalid_theme_imported', level: 'error' }) }, importValidator (parsed, filename) { if (filename.endsWith('.json')) { From bfd271a69fb43931ac32c0a96c45759089dff880 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 9 Apr 2025 00:36:07 +0300 Subject: [PATCH 4/4] export/import --- .../settings_modal/tabs/filtering_tab.js | 82 +++- .../settings_modal/tabs/filtering_tab.scss | 4 + .../settings_modal/tabs/filtering_tab.vue | 429 +++++++++--------- .../tabs/style_tab/style_tab.js | 2 +- src/i18n/en.json | 2 + 5 files changed, 294 insertions(+), 225 deletions(-) diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js index 34ade4dfc..3345cb0c9 100644 --- a/src/components/settings_modal/tabs/filtering_tab.js +++ b/src/components/settings_modal/tabs/filtering_tab.js @@ -1,8 +1,15 @@ import { cloneDeep } from 'lodash' import { mapState, mapActions } from 'pinia' -import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { v4 as uuidv4 } from 'uuid'; +import { useServerSideStorageStore } from 'src/stores/serverSideStorage' +import { useInterfaceStore } from 'src/stores/interface' + +import { + newImporter, + newExporter +} from 'src/services/export_import/export_import.js' + import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' import UnitSetting from '../helpers/unit_setting.vue' @@ -13,9 +20,10 @@ import Select from 'src/components/select/select.vue' import SharedComputedObject from '../helpers/shared_computed_object.js' +const SUPPORTED_TYPES = new Set(['word', 'regexp', 'user', 'user_regexp']) + const FilteringTab = { data () { - console.log(cloneDeep(useServerSideStorageStore().prefsStorage.simple.muteFilters)) return { replyVisibilityOptions: ['all', 'following', 'self'].map(mode => ({ key: mode, @@ -27,7 +35,44 @@ const FilteringTab = { Object.entries( useServerSideStorageStore().prefsStorage.simple.muteFilters ).map(([k]) => [k, false]) - ) + ), + exportedFilter: null, + filterImporter: newImporter({ + validator (parsed) { + if (Array.isArray(parsed)) return false + if (!SUPPORTED_TYPES.has(parsed.type)) return false + return true + }, + onImport: (data) => { + const { + enabled = true, + expires = null, + hide = false, + name = '', + value = '' + } = data + + this.createFilter({ + enabled, + expires, + hide, + name, + value + }) + }, + onImportFailure (result) { + console.error('Failure importing filter:', result) + useInterfaceStore() + .pushGlobalNotice({ + messageKey: 'settings.filter.import_failure', + level: 'error' + }) + } + }), + filterExporter: newExporter({ + filename: 'pleromafe_mute-filter', + getExportedObject: () => this.exportedFilter + }) } }, components: { @@ -83,22 +128,29 @@ const FilteringTab = { } return valid }, - createFilter () { - const filter = { - type: 'word', - value: '', - name: 'New Filter', - enabled: true, - expires: null, - hide: false, - order: this.muteFilters.length + 2 - } + createFilter (filter = { + type: 'word', + value: '', + name: 'New Filter', + enabled: true, + expires: null, + hide: false, + }) { const newId = uuidv4() + filter.order = this.muteFilters.length + 2 this.muteFiltersDraftObject[newId] = filter this.setPreference({ path: 'simple.muteFilters.' + newId , value: filter }) this.pushServerSideStorage() }, + exportFilter(id) { + this.exportedFilter = { ...this.muteFiltersDraftObject[id] } + delete this.exportedFilter.order + this.filterExporter.exportData() + }, + importFilter() { + this.filterImporter.importData() + }, copyFilter (id) { const filter = { ...this.muteFiltersDraftObject[id] } const newId = uuidv4() @@ -131,14 +183,12 @@ const FilteringTab = { } this.muteFiltersDraftObject[id] = filter this.muteFiltersDraftDirty[id] = true - console.log(this.muteFiltersDraftDirty) }, saveFilter(id) { this.setPreference({ path: 'simple.muteFilters.' + id , value: this.muteFiltersDraftObject[id] }) this.pushServerSideStorage() this.muteFiltersDraftDirty[id] = false - console.log(this.muteFiltersDraftDirty) - } + }, }, // Updating nested properties watch: { diff --git a/src/components/settings_modal/tabs/filtering_tab.scss b/src/components/settings_modal/tabs/filtering_tab.scss index 979096126..3f3fa3b58 100644 --- a/src/components/settings_modal/tabs/filtering_tab.scss +++ b/src/components/settings_modal/tabs/filtering_tab.scss @@ -62,6 +62,10 @@ max-width: 100%; justify-content: end; } + + .total { + text-align: center; + } } diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue index f7754090b..968a7a0e7 100644 --- a/src/components/settings_modal/tabs/filtering_tab.vue +++ b/src/components/settings_modal/tabs/filtering_tab.vue @@ -73,232 +73,245 @@

    {{ $t('settings.filter.mute_filter') }}

  • -
  • - - {{ $t('settings.hide_muted_statuses') }} - -
      -
    • - - {{ $t('settings.hide_filtered_statuses') }} - -
    • -
    • - - {{ $t('settings.hide_muted_threads') }} - -
    • -
    • - - {{ $t('settings.hide_muted_posts') }} - -
    • -
    -
  • -
  • - - {{ $t('settings.mute_bot_posts') }} - -
  • -
  • - - {{ $t('settings.mute_sensitive_posts') }} - -
  • -
    -
    -
    - - {{ ' ' }} + + {{ $t('settings.hide_muted_statuses') }} + +
      +
    • + + {{ $t('settings.hide_filtered_statuses') }} + +
    • +
    • + + {{ $t('settings.hide_muted_threads') }} + +
    • +
    • + + {{ $t('settings.hide_muted_posts') }} + +
    • +
    + +
  • + + {{ $t('settings.mute_bot_posts') }} + +
  • +
  • + + {{ $t('settings.mute_sensitive_posts') }} + +
  • +
    +
    +
    + + {{ ' ' }} + +
    +
    + + {{ $t('settings.filter.hide') }} + + {{ ' ' }} + + {{ $t('settings.enabled') }} + +
    +
    + + +
    +
    + + {{ ' ' }} + +
    +
    + + {{ ' ' }} +
    -
    -
    - - {{ $t('settings.filter.hide') }} - {{ ' ' }} - {{ $t('settings.enabled') }} + {{ $t('settings.filter.never_expires') }} -
    -
    - - -
    -
    - - {{ ' ' }} - -
    -
    - - {{ ' ' }} -
    - - {{ ' ' }} - - {{ $t('settings.filter.never_expires') }} - - - {{ $t('settings.filter.expired') }} - -
    -
    -
    - {{ $t('settings.filter.regexp_error') }} + {{ $t('settings.filter.expired') }} - - {{ ' ' }} - - {{ ' ' }} -
    -
    +
    + {{ $t('settings.filter.regexp_error') }} +
    +
    + + +
    - +
    + + {{ $t('settings.filter.count', { count: muteFiltersDraft.length }) }} + + + +
    +
diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js index d2162c30c..8324263cd 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.js +++ b/src/components/settings_modal/tabs/style_tab/style_tab.js @@ -643,7 +643,7 @@ export default { parser (string) { return deserialize(string) }, onImportFailure (result) { console.error('Failure importing style:', result) - this.$store.useInterfaceStore().pushGlobalNotice({ messageKey: 'settings.invalid_theme_imported', level: 'error' }) + useInterfaceStore().pushGlobalNotice({ messageKey: 'settings.invalid_theme_imported', level: 'error' }) }, onImport }) diff --git a/src/i18n/en.json b/src/i18n/en.json index 3695cb088..f5f451467 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -432,6 +432,8 @@ "export": "Export", "regexp_error": "Invalid Regular Expression", "never_expires": "Never", + "count": "{count} filter|{count} filters", + "import_failure": "The selected file is not a supported Pleroma filter.", "help": { "word": "Simple and RegExp filters test against post's content and subject.", "user": "User filter matches full user handle (user@domain) in the following: author, reply-to and mentions",