From 2e35289c3376881ca17b9330113c816a3327f245 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 3 May 2020 17:36:12 +0300 Subject: initial work on settings modal --- src/modules/interface.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src/modules') diff --git a/src/modules/interface.js b/src/modules/interface.js index 5b2762e5..e55b7290 100644 --- a/src/modules/interface.js +++ b/src/modules/interface.js @@ -1,6 +1,7 @@ import { set, delete as del } from 'vue' const defaultState = { + settingsModalState: 'hidden', settings: { currentSaveStateNotice: null, noticeClearTimeout: null, @@ -35,6 +36,24 @@ const interfaceMod = { }, setMobileLayout (state, value) { state.mobileLayout = value + }, + closeSettingsModal (state) { + state.settingsModalState = 'hidden' + }, + togglePeekSettingsModal (state) { + switch (state.settingsModalState) { + case 'minimized': + state.settingsModalState = 'visible' + return + case 'visible': + state.settingsModalState = 'minimized' + return + default: + throw new Error('Illegal minimization state of settings modal') + } + }, + openSettingsModal (state) { + state.settingsModalState = 'visible' } }, actions: { @@ -49,6 +68,15 @@ const interfaceMod = { }, setMobileLayout ({ commit }, value) { commit('setMobileLayout', value) + }, + closeSettingsModal ({ commit }) { + commit('closeSettingsModal') + }, + openSettingsModal ({ commit }) { + commit('openSettingsModal') + }, + togglePeekSettingsModal ({ commit }) { + commit('togglePeekSettingsModal') } } } -- cgit v1.2.3-70-g09d2 From b5c1d074f83d08473a19a3885f6ff5eeb95274e5 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 25 May 2020 23:38:31 +0300 Subject: fix reprööted posts not being muted properly. fix muted posts making desktop notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/status/status.js | 57 ++++++++++++++++++++++------- src/components/status/status.vue | 18 ++++++++- src/i18n/en.json | 4 +- src/modules/statuses.js | 10 ++++- src/services/status_parser/status_parser.js | 11 ++++++ 5 files changed, 83 insertions(+), 17 deletions(-) (limited to 'src/modules') diff --git a/src/components/status/status.js b/src/components/status/status.js index 9cd9d61c..95278968 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -12,7 +12,8 @@ import StatusPopover from '../status_popover/status_popover.vue' import EmojiReactions from '../emoji_reactions/emoji_reactions.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' -import { filter, unescape, uniqBy } from 'lodash' +import { muteWordHits } from '../../services/status_parser/status_parser.js' +import { unescape, uniqBy } from 'lodash' import { mapGetters, mapState } from 'vuex' const Status = { @@ -44,6 +45,12 @@ const Status = { muteWords () { return this.mergedConfig.muteWords }, + showReasonMutedThread () { + return ( + this.status.thread_muted || + (this.status.reblog && this.status.reblog.thread_muted) + ) && !this.inConversation + }, repeaterClass () { const user = this.statusoid.user return highlightClass(user) @@ -93,20 +100,44 @@ const Status = { return !!this.currentUser }, muteWordHits () { - const statusText = this.status.text.toLowerCase() - const statusSummary = this.status.summary.toLowerCase() - const hits = filter(this.muteWords, (muteWord) => { - return statusText.includes(muteWord.toLowerCase()) || statusSummary.includes(muteWord.toLowerCase()) - }) - - return hits + return muteWordHits(this.status, this.muteWords) }, muted () { - const relationship = this.$store.getters.relationship(this.status.user.id) - return !this.unmuted && ( - (!(this.inProfile && this.status.user.id === this.profileUserId) && relationship.muting) || - (!this.inConversation && this.status.thread_muted) || - this.muteWordHits.length > 0) + const { status } = this + const { reblog } = status + const relationship = this.$store.getters.relationship(status.user.id) + const relationshipReblog = reblog && this.$store.getters.relationship(reblog.user.id) + const reasonsToMute = ( + // Post is muted according to BE + status.muted || + // Reprööt of a muted post according to BE + (reblog && reblog.muted) || + // Muted user + relationship.muting || + // Muted user of a reprööt + (relationshipReblog && relationshipReblog.muting) || + // Thread is muted + status.thread_muted || + // Wordfiltered + this.muteWordHits.length > 0 + ) + const excusesNotToMute = ( + // Currently showing status + this.unmuted || + ( + this.inProfile && ( + // Don't mute user's posts on user timeline (except reblogs) + (!reblog && status.user.id === this.profileUserId) || + // Same as above but also allow self-reblogs + (reblog && reblog.user.id === this.profileUserId) + ) + ) || + // Don't mute statuses in muted conversation when said conversation is opened + (this.inConversation && status.thread_muted) + // No excuses if post has muted words + ) && !this.muteWordHits.length > 0 + + return !excusesNotToMute && reasonsToMute }, hideFilteredStatuses () { return this.mergedConfig.hideFilteredStatuses diff --git a/src/components/status/status.vue b/src/components/status/status.vue index e4c7545b..1c287aa7 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -18,10 +18,26 @@ + + {{ $t('domain_mute_card.mute') }} + + @@ -34,5 +45,9 @@ button { width: 10em; } + + .autosuggest-results & { + padding-left: 1em; + } } diff --git a/src/components/settings_modal/tabs/mutes_and_blocks_tab.js b/src/components/settings_modal/tabs/mutes_and_blocks_tab.js index b0043dbb..40a87b81 100644 --- a/src/components/settings_modal/tabs/mutes_and_blocks_tab.js +++ b/src/components/settings_modal/tabs/mutes_and_blocks_tab.js @@ -32,12 +32,12 @@ const DomainMuteList = withSubscription({ const MutesAndBlocks = { data () { return { - activeTab: 'profile', - newDomainToMute: '' + activeTab: 'profile' } }, created () { this.$store.dispatch('fetchTokens') + this.$store.dispatch('getKnownDomains') }, components: { TabSwitcher, @@ -51,6 +51,14 @@ const MutesAndBlocks = { Autosuggest, Checkbox }, + computed: { + knownDomains () { + return this.$store.state.instance.knownDomains + }, + user () { + return this.$store.state.users.currentUser + } + }, methods: { importFollows (file) { return this.$store.state.api.backendInteractor.importFollows({ file }) @@ -86,13 +94,13 @@ const MutesAndBlocks = { filterUnblockedUsers (userIds) { return reject(userIds, (userId) => { const relationship = this.$store.getters.relationship(this.userId) - return relationship.blocking || userId === this.$store.state.users.currentUser.id + return relationship.blocking || userId === this.user.id }) }, filterUnMutedUsers (userIds) { return reject(userIds, (userId) => { const relationship = this.$store.getters.relationship(this.userId) - return relationship.muting || userId === this.$store.state.users.currentUser.id + return relationship.muting || userId === this.user.id }) }, queryUserIds (query) { @@ -111,12 +119,16 @@ const MutesAndBlocks = { unmuteUsers (ids) { return this.$store.dispatch('unmuteUsers', ids) }, + filterUnMutedDomains (urls) { + return urls.filter(url => !this.user.domainMutes.includes(url)) + }, + queryKnownDomains (query) { + return new Promise((resolve, reject) => { + resolve(this.knownDomains.filter(url => url.toLowerCase().includes(query))) + }) + }, unmuteDomains (domains) { return this.$store.dispatch('unmuteDomains', domains) - }, - muteDomain () { - return this.$store.dispatch('muteDomain', this.newDomainToMute) - .then(() => { this.newDomainToMute = '' }) } } } diff --git a/src/components/settings_modal/tabs/mutes_and_blocks_tab.vue b/src/components/settings_modal/tabs/mutes_and_blocks_tab.vue index 6884b7be..5a1cf2c0 100644 --- a/src/components/settings_modal/tabs/mutes_and_blocks_tab.vue +++ b/src/components/settings_modal/tabs/mutes_and_blocks_tab.vue @@ -119,21 +119,16 @@
- - - {{ $t('domain_mute_card.mute') }} - - + +
`/api/v1/pleroma/statuses/${id}/reactions` const PLEROMA_EMOJI_REACT_URL = (id, emoji) => `/api/v1/pleroma/statuses/${id}/reactions/${emoji}` const PLEROMA_EMOJI_UNREACT_URL = (id, emoji) => `/api/v1/pleroma/statuses/${id}/reactions/${emoji}` @@ -995,6 +996,10 @@ const search2 = ({ credentials, q, resolve, limit, offset, following }) => { }) } +const fetchKnownDomains = ({ credentials }) => { + return promisedRequest({ url: MASTODON_KNOWN_DOMAIN_LIST_URL, credentials }) +} + const fetchDomainMutes = ({ credentials }) => { return promisedRequest({ url: MASTODON_DOMAIN_BLOCKS_URL, credentials }) } @@ -1193,6 +1198,7 @@ const apiService = { updateNotificationSettings, search2, searchUsers, + fetchKnownDomains, fetchDomainMutes, muteDomain, unmuteDomain -- cgit v1.2.3-70-g09d2 From 99eaec85478f384ddb0ea45a9d9c95c4dce646f5 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 8 Jun 2020 17:22:07 +0200 Subject: Messages: Load languages asynchronously. Reduces the size of the initial app bundle by about half. --- src/App.js | 3 +- .../interface_language_switcher.vue | 3 +- src/i18n/messages.js | 95 ++++++++++++++++------ src/main.js | 6 +- src/modules/config.js | 5 ++ 5 files changed, 80 insertions(+), 32 deletions(-) (limited to 'src/modules') diff --git a/src/App.js b/src/App.js index 6445335a..040138c9 100644 --- a/src/App.js +++ b/src/App.js @@ -47,7 +47,8 @@ export default { }), created () { // Load the locale from the storage - this.$i18n.locale = this.$store.getters.mergedConfig.interfaceLanguage + const val = this.$store.getters.mergedConfig.interfaceLanguage + this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) window.addEventListener('resize', this.updateMobileState) }, destroyed () { diff --git a/src/components/interface_language_switcher/interface_language_switcher.vue b/src/components/interface_language_switcher/interface_language_switcher.vue index f5ace0cc..dd6800a3 100644 --- a/src/components/interface_language_switcher/interface_language_switcher.vue +++ b/src/components/interface_language_switcher/interface_language_switcher.vue @@ -32,7 +32,7 @@ import _ from 'lodash' export default { computed: { languageCodes () { - return Object.keys(languagesObject) + return languagesObject.languages }, languageNames () { @@ -43,7 +43,6 @@ export default { get: function () { return this.$store.getters.mergedConfig.interfaceLanguage }, set: function (val) { this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) - this.$i18n.locale = val } } }, diff --git a/src/i18n/messages.js b/src/i18n/messages.js index c56ae205..a257486f 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -7,34 +7,75 @@ // sed -i -e "s/'//gm" -e 's/"/\\"/gm' -re 's/^( +)(.+?): ((.+?))?(,?)(\{?)$/\1"\2": "\4"/gm' -e 's/\"\{\"/{/g' -e 's/,"$/",/g' file.json // There's only problem that apostrophe character ' gets replaced by \\ so you have to fix it manually, sorry. +const loaders = { + ar: () => import('./ar.json'), + ca: () => import('./ca.json'), + cs: () => import('./cs.json'), + de: () => import('./de.json'), + eo: () => import('./eo.json'), + es: () => import('./es.json'), + et: () => import('./et.json'), + eu: () => import('./eu.json'), + fi: () => import('./fi.json'), + fr: () => import('./fr.json'), + ga: () => import('./ga.json'), + he: () => import('./he.json'), + hu: () => import('./hu.json'), + it: () => import('./it.json'), + ja: () => import('./ja_pedantic.json'), + ja_easy: () => import('./ja_easy.json'), + ko: () => import('./ko.json'), + nb: () => import('./nb.json'), + nl: () => import('./nl.json'), + oc: () => import('./oc.json'), + pl: () => import('./pl.json'), + pt: () => import('./pt.json'), + ro: () => import('./ro.json'), + ru: () => import('./ru.json'), + te: () => import('./te.json'), + zh: () => import('./zh.json') +} + const messages = { - ar: require('./ar.json'), - ca: require('./ca.json'), - cs: require('./cs.json'), - de: require('./de.json'), - en: require('./en.json'), - eo: require('./eo.json'), - es: require('./es.json'), - et: require('./et.json'), - eu: require('./eu.json'), - fi: require('./fi.json'), - fr: require('./fr.json'), - ga: require('./ga.json'), - he: require('./he.json'), - hu: require('./hu.json'), - it: require('./it.json'), - ja: require('./ja_pedantic.json'), - ja_easy: require('./ja_easy.json'), - ko: require('./ko.json'), - nb: require('./nb.json'), - nl: require('./nl.json'), - oc: require('./oc.json'), - pl: require('./pl.json'), - pt: require('./pt.json'), - ro: require('./ro.json'), - ru: require('./ru.json'), - te: require('./te.json'), - zh: require('./zh.json') + languages: [ + 'ar', + 'ca', + 'cs', + 'de', + 'en', + 'eo', + 'es', + 'et', + 'eu', + 'fi', + 'fr', + 'ga', + 'he', + 'hu', + 'it', + 'ja', + 'ja_easy', + 'ko', + 'nb', + 'nl', + 'oc', + 'pl', + 'pt', + 'ro', + 'ru', + 'te', + 'zh' + ], + default: { + en: require('./en.json') + }, + setLanguage: async (i18n, language) => { + if (loaders[language]) { + let messages = await loaders[language]() + i18n.setLocaleMessage(language, messages) + } + i18n.locale = language + } } export default messages diff --git a/src/main.js b/src/main.js index be4213fa..9a201e4f 100644 --- a/src/main.js +++ b/src/main.js @@ -46,11 +46,13 @@ Vue.use(VBodyScrollLock) const i18n = new VueI18n({ // By default, use the browser locale, we will update it if neccessary - locale: currentLocale, + locale: 'en', fallbackLocale: 'en', - messages + messages: messages.default }) +messages.setLanguage(i18n, currentLocale) + const persistedStateOptions = { paths: [ 'config', diff --git a/src/modules/config.js b/src/modules/config.js index b6b1b241..47b24d77 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -1,5 +1,6 @@ import { set, delete as del } from 'vue' import { setPreset, applyTheme } from '../services/style_setter/style_setter.js' +import messages from '../i18n/messages' const browserLocale = (window.navigator.language || 'en').split('-')[0] @@ -115,6 +116,10 @@ const config = { case 'customTheme': case 'customThemeSource': applyTheme(value) + break + case 'interfaceLanguage': + messages.setLanguage(this.getters.i18n, value) + break } } } -- cgit v1.2.3-70-g09d2 From a52a393266744560c6c6b2cbd24da812d35562fb Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 11 Jun 2020 15:22:31 +0200 Subject: NotificationUtils: Extract preparation of notification object. --- src/modules/statuses.js | 41 ++------------------- .../notification_utils/notification_utils.js | 42 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 38 deletions(-) (limited to 'src/modules') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 9a2e0df1..073b15f1 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -13,7 +13,7 @@ import { omitBy } from 'lodash' import { set } from 'vue' -import { isStatusNotification } from '../services/notification_utils/notification_utils.js' +import { isStatusNotification, prepareNotificationObject } from '../services/notification_utils/notification_utils.js' import apiService from '../services/api/api.service.js' import { muteWordHits } from '../services/status_parser/status_parser.js' @@ -344,42 +344,7 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot state.notifications.idStore[notification.id] = notification if ('Notification' in window && window.Notification.permission === 'granted') { - const notifObj = {} - const status = notification.status - const title = notification.from_profile.name - notifObj.icon = notification.from_profile.profile_image_url - let i18nString - switch (notification.type) { - case 'like': - i18nString = 'favorited_you' - break - case 'repeat': - i18nString = 'repeated_you' - break - case 'follow': - i18nString = 'followed_you' - break - case 'move': - i18nString = 'migrated_to' - break - case 'follow_request': - i18nString = 'follow_request' - break - } - - if (notification.type === 'pleroma:emoji_reaction') { - notifObj.body = rootGetters.i18n.t('notifications.reacted_with', [notification.emoji]) - } else if (i18nString) { - notifObj.body = rootGetters.i18n.t('notifications.' + i18nString) - } else if (isStatusNotification(notification.type)) { - notifObj.body = notification.status.text - } - - // Shows first attached non-nsfw image, if any. Should add configuration for this somehow... - if (status && status.attachments && status.attachments.length > 0 && !status.nsfw && - status.attachments[0].mimetype.startsWith('image/')) { - notifObj.image = status.attachments[0].url - } + const notifObj = prepareNotificationObject(notification, rootGetters.i18n) const reasonsToMuteNotif = ( notification.seen || @@ -393,7 +358,7 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot ) ) if (!reasonsToMuteNotif) { - let desktopNotification = new window.Notification(title, notifObj) + let desktopNotification = new window.Notification(notifObj.title, notifObj) // Chrome is known for not closing notifications automatically // according to MDN, anyway. setTimeout(desktopNotification.close.bind(desktopNotification), 5000) diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js index eb479227..4576ea83 100644 --- a/src/services/notification_utils/notification_utils.js +++ b/src/services/notification_utils/notification_utils.js @@ -43,3 +43,45 @@ export const filteredNotificationsFromStore = (store, types) => { export const unseenNotificationsFromStore = store => filter(filteredNotificationsFromStore(store), ({ seen }) => !seen) + +export const prepareNotificationObject = (notification, i18n) => { + const notifObj = {} + const status = notification.status + const title = notification.from_profile.name + notifObj.title = title + notifObj.icon = notification.from_profile.profile_image_url + let i18nString + switch (notification.type) { + case 'like': + i18nString = 'favorited_you' + break + case 'repeat': + i18nString = 'repeated_you' + break + case 'follow': + i18nString = 'followed_you' + break + case 'move': + i18nString = 'migrated_to' + break + case 'follow_request': + i18nString = 'follow_request' + break + } + + if (notification.type === 'pleroma:emoji_reaction') { + notifObj.body = i18n.t('notifications.reacted_with', [notification.emoji]) + } else if (i18nString) { + notifObj.body = i18n.t('notifications.' + i18nString) + } else if (isStatusNotification(notification.type)) { + notifObj.body = notification.status.text + } + + // Shows first attached non-nsfw image, if any. Should add configuration for this somehow... + if (status && status.attachments && status.attachments.length > 0 && !status.nsfw && + status.attachments[0].mimetype.startsWith('image/')) { + notifObj.image = status.attachments[0].url + } + + return notifObj +} -- cgit v1.2.3-70-g09d2 From 9c884fef11e52541ab64508c9a9e0b8694432cbb Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Thu, 18 Jun 2020 12:29:13 +0300 Subject: remove search blocker, fix debounce params --- src/components/emoji_input/suggestor.js | 8 ++++---- src/modules/users.js | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'src/modules') diff --git a/src/components/emoji_input/suggestor.js b/src/components/emoji_input/suggestor.js index 15a71eff..91d5cfb9 100644 --- a/src/components/emoji_input/suggestor.js +++ b/src/components/emoji_input/suggestor.js @@ -1,4 +1,4 @@ -import { debounce } from 'lodash' +import debounce from 'lodash/debounce' /** * suggest - generates a suggestor function to be used by emoji-input * data: object providing source information for specific types of suggestions: @@ -13,7 +13,7 @@ import { debounce } from 'lodash' const debounceUserSearch = debounce((data, input) => { data.updateUsersList(input) -}, 500, { leading: true, trailing: false }) +}, 500) export default data => input => { const firstChar = input[0] @@ -97,8 +97,8 @@ export const suggestUsers = data => input => { replacement: '@' + screen_name + ' ' })) - // BE search users if there are no matches - if (newUsers.length === 0 && data.updateUsersList) { + // BE search users to get more comprehensive results + if (data.updateUsersList) { debounceUserSearch(data, noPrefix) } return newUsers diff --git a/src/modules/users.js b/src/modules/users.js index f9329f2a..a640fb3b 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -225,6 +225,12 @@ export const mutations = { signUpFailure (state, errors) { state.signUpPending = false state.signUpErrors = errors + }, + addRecentQuery (state, query) { + state.recentQueries = state.recentQueries.concat(query) + if (state.recentQueries.length > 10) { + state.recentQueries = state.recentQueries.slice(1) + } } } @@ -251,7 +257,8 @@ export const defaultState = { usersObject: {}, signUpPending: false, signUpErrors: [], - relationships: {} + relationships: {}, + recentQueries: [] } const users = { @@ -428,10 +435,15 @@ const users = { store.commit('setUserForNotification', notification) }) }, - searchUsers (store, { query }) { - return store.rootState.api.backendInteractor.searchUsers({ query }) + searchUsers ({ rootState, commit }, { query }) { + // Don't fetch if this query was already done recently + if (rootState.users.recentQueries.includes(query)) { + return [] + } + return rootState.api.backendInteractor.searchUsers({ query }) .then((users) => { - store.commit('addNewUsers', users) + commit('addRecentQuery', query) + commit('addNewUsers', users) return users }) }, -- cgit v1.2.3-70-g09d2 From fa7bcb74cecb8af095e6e22271243f2d51835f39 Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Thu, 18 Jun 2020 13:00:09 +0300 Subject: return the correct promise type from action --- src/modules/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules') diff --git a/src/modules/users.js b/src/modules/users.js index a640fb3b..df710ac9 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -438,7 +438,7 @@ const users = { searchUsers ({ rootState, commit }, { query }) { // Don't fetch if this query was already done recently if (rootState.users.recentQueries.includes(query)) { - return [] + return Promise.resolve([]) } return rootState.api.backendInteractor.searchUsers({ query }) .then((users) => { -- cgit v1.2.3-70-g09d2 From 4e0b4427a969b2d0584a3a1c1ffd3fe3fbfc2998 Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Thu, 18 Jun 2020 14:19:21 +0300 Subject: remove recentqueries thing --- src/modules/users.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'src/modules') diff --git a/src/modules/users.js b/src/modules/users.js index df710ac9..5e32bb49 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -225,12 +225,6 @@ export const mutations = { signUpFailure (state, errors) { state.signUpPending = false state.signUpErrors = errors - }, - addRecentQuery (state, query) { - state.recentQueries = state.recentQueries.concat(query) - if (state.recentQueries.length > 10) { - state.recentQueries = state.recentQueries.slice(1) - } } } @@ -257,8 +251,7 @@ export const defaultState = { usersObject: {}, signUpPending: false, signUpErrors: [], - relationships: {}, - recentQueries: [] + relationships: {} } const users = { @@ -436,13 +429,8 @@ const users = { }) }, searchUsers ({ rootState, commit }, { query }) { - // Don't fetch if this query was already done recently - if (rootState.users.recentQueries.includes(query)) { - return Promise.resolve([]) - } return rootState.api.backendInteractor.searchUsers({ query }) .then((users) => { - commit('addRecentQuery', query) commit('addNewUsers', users) return users }) -- cgit v1.2.3-70-g09d2