diff options
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/announcements.js | 135 | ||||
| -rw-r--r-- | src/modules/api.js | 2 | ||||
| -rw-r--r-- | src/modules/config.js | 4 | ||||
| -rw-r--r-- | src/modules/instance.js | 14 | ||||
| -rw-r--r-- | src/modules/serverSideStorage.js | 15 | ||||
| -rw-r--r-- | src/modules/statuses.js | 4 | ||||
| -rw-r--r-- | src/modules/users.js | 10 |
7 files changed, 175 insertions, 9 deletions
diff --git a/src/modules/announcements.js b/src/modules/announcements.js new file mode 100644 index 00000000..e4d2d2b0 --- /dev/null +++ b/src/modules/announcements.js @@ -0,0 +1,135 @@ +const FETCH_ANNOUNCEMENT_INTERVAL_MS = 1000 * 60 * 5 + +export const defaultState = { + announcements: [], + supportsAnnouncements: true, + fetchAnnouncementsTimer: undefined +} + +export const mutations = { + setAnnouncements (state, announcements) { + state.announcements = announcements + }, + setAnnouncementRead (state, { id, read }) { + const index = state.announcements.findIndex(a => a.id === id) + + if (index < 0) { + return + } + + state.announcements[index].read = read + }, + setFetchAnnouncementsTimer (state, timer) { + state.fetchAnnouncementsTimer = timer + }, + setSupportsAnnouncements (state, supportsAnnouncements) { + state.supportsAnnouncements = supportsAnnouncements + } +} + +export const getters = { + unreadAnnouncementCount (state, _getters, rootState) { + if (!rootState.users.currentUser) { + return 0 + } + + const unread = state.announcements.filter(announcement => !(announcement.inactive || announcement.read)) + return unread.length + } +} + +const announcements = { + state: defaultState, + mutations, + getters, + actions: { + fetchAnnouncements (store) { + if (!store.state.supportsAnnouncements) { + return Promise.resolve() + } + + const currentUser = store.rootState.users.currentUser + const isAdmin = currentUser && currentUser.role === 'admin' + + const getAnnouncements = async () => { + if (!isAdmin) { + return store.rootState.api.backendInteractor.fetchAnnouncements() + } + + const all = await store.rootState.api.backendInteractor.adminFetchAnnouncements() + const visible = await store.rootState.api.backendInteractor.fetchAnnouncements() + const visibleObject = visible.reduce((a, c) => { + a[c.id] = c + return a + }, {}) + const getWithinVisible = announcement => visibleObject[announcement.id] + + all.forEach(announcement => { + const visibleAnnouncement = getWithinVisible(announcement) + if (!visibleAnnouncement) { + announcement.inactive = true + } else { + announcement.read = visibleAnnouncement.read + } + }) + + return all + } + + return getAnnouncements() + .then(announcements => { + store.commit('setAnnouncements', announcements) + }) + .catch(error => { + // If and only if backend does not support announcements, it would return 404. + // In this case, silently ignores it. + if (error && error.statusCode === 404) { + store.commit('setSupportsAnnouncements', false) + } else { + throw error + } + }) + }, + markAnnouncementAsRead (store, id) { + return store.rootState.api.backendInteractor.dismissAnnouncement({ id }) + .then(() => { + store.commit('setAnnouncementRead', { id, read: true }) + }) + }, + startFetchingAnnouncements (store) { + if (store.state.fetchAnnouncementsTimer) { + return + } + + const interval = setInterval(() => store.dispatch('fetchAnnouncements'), FETCH_ANNOUNCEMENT_INTERVAL_MS) + store.commit('setFetchAnnouncementsTimer', interval) + + return store.dispatch('fetchAnnouncements') + }, + stopFetchingAnnouncements (store) { + const interval = store.state.fetchAnnouncementsTimer + store.commit('setFetchAnnouncementsTimer', undefined) + clearInterval(interval) + }, + postAnnouncement (store, { content, startsAt, endsAt, allDay }) { + return store.rootState.api.backendInteractor.postAnnouncement({ content, startsAt, endsAt, allDay }) + .then(() => { + return store.dispatch('fetchAnnouncements') + }) + }, + editAnnouncement (store, { id, content, startsAt, endsAt, allDay }) { + return store.rootState.api.backendInteractor.editAnnouncement({ id, content, startsAt, endsAt, allDay }) + .then(() => { + return store.dispatch('fetchAnnouncements') + }) + }, + deleteAnnouncement (store, id) { + return store.rootState.api.backendInteractor.deleteAnnouncement({ id }) + .then(() => { + return store.dispatch('fetchAnnouncements') + }) + } + } +} + +export default announcements diff --git a/src/modules/api.js b/src/modules/api.js index 0acc03f1..fee584e8 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -216,7 +216,7 @@ const api = { if (!fetcher) return store.commit('removeFetcher', { fetcherName: timeline, fetcher }) }, - fetchTimeline (store, timeline, { ...rest }) { + fetchTimeline (store, { timeline, ...rest }) { store.state.backendInteractor.fetchTimeline({ store, timeline, diff --git a/src/modules/config.js b/src/modules/config.js index c966602e..3cd6888f 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -83,8 +83,8 @@ export const defaultState = { useContainFit: true, disableStickyHeaders: false, showScrollbars: false, - userPopoverAvatarAction: 'close', - userPopoverOverlay: true, + userPopoverAvatarAction: 'open', + userPopoverOverlay: false, sidebarColumnWidth: '25rem', contentColumnWidth: '45rem', notifsColumnWidth: '25rem', diff --git a/src/modules/instance.js b/src/modules/instance.js index b1bc9779..3b15e62e 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -36,6 +36,8 @@ const REGIONAL_INDICATORS = (() => { return res })() +const REMOTE_INTERACTION_URL = '/main/ostatus' + const defaultState = { // Stuff from apiConfig name: 'Pleroma FE', @@ -214,6 +216,18 @@ const instance = { }, instanceDomain (state) { return new URL(state.server).hostname + }, + remoteInteractionLink (state) { + const server = state.server.endsWith('/') ? state.server.slice(0, -1) : state.server + const link = server + REMOTE_INTERACTION_URL + + return ({ statusId, nickname }) => { + if (statusId) { + return `${link}?status_id=${statusId}` + } else { + return `${link}?nickname=${nickname}` + } + } } }, actions: { diff --git a/src/modules/serverSideStorage.js b/src/modules/serverSideStorage.js index 56164be7..c933ce8d 100644 --- a/src/modules/serverSideStorage.js +++ b/src/modules/serverSideStorage.js @@ -1,5 +1,5 @@ import { toRaw } from 'vue' -import { isEqual, cloneDeep, set, get, clamp, flatten, groupBy, findLastIndex, takeRight } from 'lodash' +import { isEqual, cloneDeep, set, get, clamp, flatten, groupBy, findLastIndex, takeRight, uniqWith } from 'lodash' import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js' export const VERSION = 1 @@ -149,12 +149,21 @@ const _mergeJournal = (...journals) => { if (path.startsWith('collections')) { const lastRemoveIndex = findLastIndex(journal, ({ operation }) => operation === 'removeFromCollection') // everything before last remove is unimportant + let remainder if (lastRemoveIndex > 0) { - return journal.slice(lastRemoveIndex) + remainder = journal.slice(lastRemoveIndex) } else { // everything else doesn't need trimming - return journal + remainder = journal } + return uniqWith(remainder, (a, b) => { + if (a.path !== b.path) { return false } + if (a.operation !== b.operation) { return false } + if (a.operation === 'addToCollection') { + return a.args[0] === b.args[0] + } + return false + }) } else if (path.startsWith('simple')) { // Only the last record is important return takeRight(journal) diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 803d7019..5a5c7b1b 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -761,8 +761,8 @@ const statuses = { rootState.api.backendInteractor.fetchRebloggedByUsers({ id }) .then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })) }, - search (store, { q, resolve, limit, offset, following }) { - return store.rootState.api.backendInteractor.search2({ q, resolve, limit, offset, following }) + search (store, { q, resolve, limit, offset, following, type }) { + return store.rootState.api.backendInteractor.search2({ q, resolve, limit, offset, following, type }) .then((data) => { store.commit('addNewUsers', data.accounts) store.commit('addNewStatuses', { statuses: data.statuses }) diff --git a/src/modules/users.js b/src/modules/users.js index eef87c2c..053e44b6 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -56,6 +56,11 @@ const removeUserFromFollowers = (store, id) => { .then((relationship) => store.commit('updateUserRelationship', [relationship])) } +const editUserNote = (store, { id, comment }) => { + return store.rootState.api.backendInteractor.editUserNote({ id, comment }) + .then((relationship) => store.commit('updateUserRelationship', [relationship])) +} + const muteUser = (store, id) => { const predictedRelationship = store.state.relationships[id] || { id } predictedRelationship.muting = true @@ -335,6 +340,9 @@ const users = { unblockUsers (store, ids = []) { return Promise.all(ids.map(id => unblockUser(store, id))) }, + editUserNote (store, args) { + return editUserNote(store, args) + }, fetchMutes (store) { return store.rootState.api.backendInteractor.fetchMutes() .then((mutes) => { @@ -588,7 +596,7 @@ const users = { } if (store.getters.mergedConfig.useStreamingApi) { - store.dispatch('fetchTimeline', 'friends', { since: null }) + store.dispatch('fetchTimeline', { timeline: 'friends', since: null }) store.dispatch('fetchNotifications', { since: null }) store.dispatch('enableMastoSockets', true).catch((error) => { console.error('Failed initializing MastoAPI Streaming socket', error) |
