export/import

This commit is contained in:
Henry Jameson 2025-04-09 00:36:07 +03:00
commit bfd271a69f
5 changed files with 294 additions and 225 deletions

View file

@ -1,8 +1,15 @@
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import { mapState, mapActions } from 'pinia' import { mapState, mapActions } from 'pinia'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
import { v4 as uuidv4 } from 'uuid'; 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 BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import UnitSetting from '../helpers/unit_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' import SharedComputedObject from '../helpers/shared_computed_object.js'
const SUPPORTED_TYPES = new Set(['word', 'regexp', 'user', 'user_regexp'])
const FilteringTab = { const FilteringTab = {
data () { data () {
console.log(cloneDeep(useServerSideStorageStore().prefsStorage.simple.muteFilters))
return { return {
replyVisibilityOptions: ['all', 'following', 'self'].map(mode => ({ replyVisibilityOptions: ['all', 'following', 'self'].map(mode => ({
key: mode, key: mode,
@ -27,7 +35,44 @@ const FilteringTab = {
Object.entries( Object.entries(
useServerSideStorageStore().prefsStorage.simple.muteFilters useServerSideStorageStore().prefsStorage.simple.muteFilters
).map(([k]) => [k, false]) ).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: { components: {
@ -83,22 +128,29 @@ const FilteringTab = {
} }
return valid return valid
}, },
createFilter () { createFilter (filter = {
const filter = {
type: 'word', type: 'word',
value: '', value: '',
name: 'New Filter', name: 'New Filter',
enabled: true, enabled: true,
expires: null, expires: null,
hide: false, hide: false,
order: this.muteFilters.length + 2 }) {
}
const newId = uuidv4() const newId = uuidv4()
filter.order = this.muteFilters.length + 2
this.muteFiltersDraftObject[newId] = filter this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId , value: filter }) this.setPreference({ path: 'simple.muteFilters.' + newId , value: filter })
this.pushServerSideStorage() this.pushServerSideStorage()
}, },
exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] }
delete this.exportedFilter.order
this.filterExporter.exportData()
},
importFilter() {
this.filterImporter.importData()
},
copyFilter (id) { copyFilter (id) {
const filter = { ...this.muteFiltersDraftObject[id] } const filter = { ...this.muteFiltersDraftObject[id] }
const newId = uuidv4() const newId = uuidv4()
@ -131,14 +183,12 @@ const FilteringTab = {
} }
this.muteFiltersDraftObject[id] = filter this.muteFiltersDraftObject[id] = filter
this.muteFiltersDraftDirty[id] = true this.muteFiltersDraftDirty[id] = true
console.log(this.muteFiltersDraftDirty)
}, },
saveFilter(id) { saveFilter(id) {
this.setPreference({ path: 'simple.muteFilters.' + id , value: this.muteFiltersDraftObject[id] }) this.setPreference({ path: 'simple.muteFilters.' + id , value: this.muteFiltersDraftObject[id] })
this.pushServerSideStorage() this.pushServerSideStorage()
this.muteFiltersDraftDirty[id] = false this.muteFiltersDraftDirty[id] = false
console.log(this.muteFiltersDraftDirty) },
}
}, },
// Updating nested properties // Updating nested properties
watch: { watch: {

View file

@ -62,6 +62,10 @@
max-width: 100%; max-width: 100%;
justify-content: end; justify-content: end;
} }
.total {
text-align: center;
}
} }

View file

@ -72,7 +72,6 @@
</ul> </ul>
<ul class="setting-list"> <ul class="setting-list">
<h2>{{ $t('settings.filter.mute_filter') }}</h2> <h2>{{ $t('settings.filter.mute_filter') }}</h2>
<li>
<li> <li>
<BooleanSetting path="hideFilteredStatuses"> <BooleanSetting path="hideFilteredStatuses">
{{ $t('settings.hide_muted_statuses') }} {{ $t('settings.hide_muted_statuses') }}
@ -254,21 +253,13 @@
</span> </span>
</div> </div>
</div> </div>
<div class="filter-buttons"> <div
<span
v-if="!checkRegexValid(filter[0])" v-if="!checkRegexValid(filter[0])"
class="alert error" class="alert error"
> >
{{ $t('settings.filter.regexp_error') }} {{ $t('settings.filter.regexp_error') }}
</span> </div>
<button <div class="filter-buttons">
class="copy-button button-default"
type="button"
@click="copyFilter(filter[0])"
>
{{ $t('settings.filter.copy') }}
</button>
{{ ' ' }}
<button <button
class="delete-button button-default -danger" class="delete-button button-default -danger"
type="button" type="button"
@ -276,7 +267,20 @@
> >
{{ $t('settings.filter.delete') }} {{ $t('settings.filter.delete') }}
</button> </button>
{{ ' ' }} <button
class="export-button button-default"
type="button"
@click="exportFilter(filter[0])"
>
{{ $t('settings.filter.export') }}
</button>
<button
class="copy-button button-default"
type="button"
@click="copyFilter(filter[0])"
>
{{ $t('settings.filter.copy') }}
</button>
<button <button
class="save-button button-default" class="save-button button-default"
:class="{ disabled: !muteFiltersDraftDirty[filter[0]] }" :class="{ disabled: !muteFiltersDraftDirty[filter[0]] }"
@ -288,7 +292,10 @@
</button> </button>
</div> </div>
</div> </div>
<div class="mute-filter"> <div class="mute-filter new-filter">
<span class="total">
{{ $t('settings.filter.count', { count: muteFiltersDraft.length }) }}
</span>
<button <button
class="add-button button-default" class="add-button button-default"
type="button" type="button"
@ -296,9 +303,15 @@
> >
{{ $t('settings.filter.new') }} {{ $t('settings.filter.new') }}
</button> </button>
<button
class="add-button button-default"
type="button"
@click="importFilter()"
>
{{ $t('settings.filter.import') }}
</button>
</div> </div>
</div> </div>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View file

@ -643,7 +643,7 @@ export default {
parser (string) { return deserialize(string) }, parser (string) { return deserialize(string) },
onImportFailure (result) { onImportFailure (result) {
console.error('Failure importing style:', 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 onImport
}) })

View file

@ -432,6 +432,8 @@
"export": "Export", "export": "Export",
"regexp_error": "Invalid Regular Expression", "regexp_error": "Invalid Regular Expression",
"never_expires": "Never", "never_expires": "Never",
"count": "{count} filter|{count} filters",
"import_failure": "The selected file is not a supported Pleroma filter.",
"help": { "help": {
"word": "Simple and RegExp filters test against post's content and subject.", "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", "user": "User filter matches full user handle (user@domain) in the following: author, reply-to and mentions",