diff --git a/changelog.d/mutes-sync.add b/changelog.d/mutes-sync.add
new file mode 100644
index 000000000..e8e0e462a
--- /dev/null
+++ b/changelog.d/mutes-sync.add
@@ -0,0 +1 @@
+Synchronized mutes, advanced mute control (regexp, expiry, naming)
diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js
index bbd1e8631..4b404023d 100644
--- a/src/components/settings_modal/tabs/filtering_tab.js
+++ b/src/components/settings_modal/tabs/filtering_tab.js
@@ -1,4 +1,4 @@
-import { throttle } from 'lodash'
+import { throttle, cloneDeep } from 'lodash'
import { mapState, mapActions } from 'pinia'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
import { v4 as uuidv4 } from 'uuid';
@@ -14,12 +14,19 @@ import SharedComputedObject from '../helpers/shared_computed_object.js'
const FilteringTab = {
data () {
+ console.log(cloneDeep(useServerSideStorageStore().prefsStorage.simple.muteFilters))
return {
replyVisibilityOptions: ['all', 'following', 'self'].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.reply_visibility_${mode}`)
- }))
+ })),
+ muteFiltersDraftObject: cloneDeep(useServerSideStorageStore().prefsStorage.simple.muteFilters),
+ muteFiltersDraftDirty: Object.fromEntries(
+ Object.entries(
+ useServerSideStorageStore().prefsStorage.simple.muteFilters
+ ).map(([k]) => [k, false])
+ )
}
},
components: {
@@ -38,12 +45,13 @@ const FilteringTab = {
muteFilters: store => Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: store => store.prefsStorage.simple.muteFilters
}
- )
+ ),
+ muteFiltersDraft () {
+ return Object.entries(this.muteFiltersDraftObject)
+ }
},
methods: {
- ...mapActions(useServerSideStorageStore, ['unsetPreference']),
- pushServerSideStorage: throttle(() => useServerSideStorageStore().pushServerSideStorage(), 500),
- setPreference: throttle(x => useServerSideStorageStore().setPreference(x), 500),
+ ...mapActions(useServerSideStorageStore, ['setPreference', 'unsetPreference', 'pushServerSideStorage']),
getDatetimeLocal (timestamp) {
const date = new Date(timestamp)
const datetime = [
@@ -84,22 +92,25 @@ const FilteringTab = {
}
const newId = uuidv4()
+ this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId , value: filter })
this.pushServerSideStorage()
},
copyFilter (id) {
- const filter = { ...this.muteFiltersObject[id] }
+ const filter = { ...this.muteFiltersDraftObject[id] }
const newId = uuidv4()
+ this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId , value: filter })
this.pushServerSideStorage()
},
deleteFilter (id) {
+ delete this.muteFiltersDraftObject[id]
this.unsetPreference({ path: 'simple.muteFilters.' + id , value: null })
this.pushServerSideStorage()
},
updateFilter(id, field, value) {
- const filter = { ...this.muteFiltersObject[id] }
+ const filter = { ...this.muteFiltersDraftObject[id] }
if (field === 'expires-never') {
// filter[field] = value
if (!value) {
@@ -115,8 +126,15 @@ const FilteringTab = {
} else {
filter[field] = value
}
- this.setPreference({ path: 'simple.muteFilters.' + id , value: filter })
+ 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
diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue
index d3c18a184..be4ac3fcf 100644
--- a/src/components/settings_modal/tabs/filtering_tab.vue
+++ b/src/components/settings_modal/tabs/filtering_tab.vue
@@ -76,7 +76,7 @@
@@ -201,6 +201,16 @@
>
{{ $t('settings.filter.delete') }}
+ {{ ' ' }}
+
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 4e62a365c..da2d79a69 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -422,6 +422,7 @@
"expires": "Expires",
"expired": "Expired",
"copy": "Copy filter",
+ "save": "Save filter",
"delete": "Remove filter",
"new": "Create filter",
"regexp_error": "Invalid Regular Expression",
diff --git a/src/modules/config_declaration.js b/src/modules/config_declaration.js
new file mode 100644
index 000000000..05fb250e6
--- /dev/null
+++ b/src/modules/config_declaration.js
@@ -0,0 +1,41 @@
+export const CONFIG_MIGRATION = 1
+import { v4 as uuidv4 } from 'uuid';
+
+// for future use
+/*
+const simpleDeclaration = {
+ store: 'server-side',
+ migration(serverside, rootState) {
+ serverside.setPreference({ path: 'simple.' + field, value: rootState.config[oldField ?? field] })
+ }
+}
+*/
+
+export const declarations = [
+ {
+ field: 'muteFilters',
+ store: 'server-side',
+ migrationFlag: 'configMigration',
+ migrationNum: 1,
+ description: 'Mute filters, wordfilter/regexp/etc',
+ valueType: 'complex',
+ migration (serverside, rootState) {
+ rootState.config.muteWords.forEach((word, order) => {
+ const uniqueId = uuidv4()
+
+ serverside.setPreference({
+ path: 'simple.muteFilters.' + uniqueId,
+ value: {
+ type: 'word',
+ value: word,
+ name: word,
+ enabled: true,
+ expires: null,
+ hide: false,
+ order
+ }
+ })
+ })
+ }
+ }
+]
diff --git a/src/modules/users.js b/src/modules/users.js
index d9dae91ea..d5ef6cdf5 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -1,5 +1,4 @@
import { compact, map, each, mergeWith, last, concat, uniq, isArray } from 'lodash'
-import { v4 as uuidv4 } from 'uuid';
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import { windowWidth, windowHeight } from '../services/window_utils/window_utils'
@@ -9,7 +8,9 @@ import { registerPushNotifications, unregisterPushNotifications } from '../servi
import { useInterfaceStore } from 'src/stores/interface.js'
import { useOAuthStore } from 'src/stores/oauth.js'
-import { useServerSideStorageStore, CONFIG_MIGRATION } from 'src/stores/serverSideStorage'
+import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
+
+import { declarations } from 'src/modules/config_declaration'
// TODO: Unify with mergeOrAdd in statuses.js
export const mergeOrAdd = (arr, obj, item) => {
@@ -637,33 +638,17 @@ const users = {
/**/
const { configMigration } = useServerSideStorageStore().flagStorage
-
- // Wordfilter migration
- if (configMigration < 1) {
- // Convert existing wordfilter into synced one
- store.rootState.config.muteWords.forEach((word, order) => {
- const uniqueId = uuidv4()
-
- useServerSideStorageStore().setPreference({
- path: 'simple.muteFilters.' + uniqueId,
- value: {
- type: 'word',
- value: word,
- name: word,
- enabled: true,
- expires: null,
- hide: false,
- order
- }
- })
+ declarations
+ .filter(x => {
+ return x.store === 'server-side' &&
+ (x.migrationNum ?? x.migrationNum > configMigration)
+ })
+ .toSorted((a, b) => a.configMigration - b.configMigration)
+ .forEach(value => {
+ value.migration(useServerSideStorageStore(), store.rootState)
+ useServerSideStorageStore().setFlag({ flag: 'configMigration', value: value.migrationNum })
+ useServerSideStorageStore().pushServerSideStorage()
})
- }
-
- if (configMigration < CONFIG_MIGRATION) {
- // Update the flag
- useServerSideStorageStore().setFlag({ flag: 'configMigration', value: CONFIG_MIGRATION })
- useServerSideStorageStore().pushServerSideStorage()
- }
if (user.token) {
dispatch('setWsToken', user.token)
diff --git a/src/services/status_parser/status_parser.js b/src/services/status_parser/status_parser.js
index 96624fc5e..64be68d78 100644
--- a/src/services/status_parser/status_parser.js
+++ b/src/services/status_parser/status_parser.js
@@ -5,6 +5,7 @@ export const muteFilterHits = (muteFilters, status) => {
return muteFilters.toSorted((a,b) => b.order - a.order).map(filter => {
const { hide, expires, name, value, type, enabled} = filter
if (!enabled) return false
+ if (value === '') return false
if (expires !== null && expires < Date.now()) return false
switch (type) {
case 'word': {