From f36f11045e54850a20a35f8a1b89cd816feac77b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Jun 2025 14:57:34 +0300 Subject: [PATCH 01/22] add Akkoma compatibility (tested on IceShrimp) --- index.html | 1 + src/boot/after_store.js | 3 ++- src/components/announcement/announcement.js | 2 +- src/components/interactions/interactions.js | 2 +- src/components/moderation_tools/moderation_tools.js | 2 +- src/components/navigation/filter.js | 4 ++-- src/components/settings_modal/tabs/notifications_tab.js | 2 +- .../status_action_buttons/buttons_definitions.js | 2 +- src/components/user_card/user_card.js | 5 ++++- src/modules/api.js | 1 + src/modules/statuses.js | 7 +++++++ src/modules/users.js | 7 +++++-- src/stores/announcements.js | 2 +- 13 files changed, 28 insertions(+), 12 deletions(-) diff --git a/index.html b/index.html index a2f928361..f279ed01a 100644 --- a/index.html +++ b/index.html @@ -5,6 +5,7 @@ + diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 1b133a089..42cd14b0a 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -242,7 +242,8 @@ const resolveStaffAccounts = ({ store, accounts }) => { const getNodeInfo = async ({ store }) => { try { - const res = await preloadFetch('/nodeinfo/2.1.json') + let res = await preloadFetch('/nodeinfo/2.1.json') + if (!res.ok) res = await preloadFetch('/nodeinfo/2.0.json') if (res.ok) { const data = await res.json() const metadata = data.metadata diff --git a/src/components/announcement/announcement.js b/src/components/announcement/announcement.js index d1b8257d8..a1b20bf60 100644 --- a/src/components/announcement/announcement.js +++ b/src/components/announcement/announcement.js @@ -29,7 +29,7 @@ const Announcement = { currentUser: state => state.users.currentUser }), canEditAnnouncement () { - return this.currentUser && this.currentUser.privileges.includes('announcements_manage_announcements') + return this.currentUser && this.currentUser.privileges?.includes('announcements_manage_announcements') }, content () { return this.announcement.content diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js index fc441b908..458dca859 100644 --- a/src/components/interactions/interactions.js +++ b/src/components/interactions/interactions.js @@ -16,7 +16,7 @@ const Interactions = { return { allowFollowingMove: this.$store.state.users.currentUser.allow_following_move, filterMode: tabModeDict.mentions, - canSeeReports: this.$store.state.users.currentUser.privileges.includes('reports_manage_reports') + canSeeReports: this.$store.state.users.currentUser.privileges?.includes('reports_manage_reports') } }, methods: { diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js index bd57a353a..a0c5884d4 100644 --- a/src/components/moderation_tools/moderation_tools.js +++ b/src/components/moderation_tools/moderation_tools.js @@ -59,7 +59,7 @@ const ModerationTools = { return this.tagsSet.has(tagName) }, privileged (privilege) { - return this.$store.state.users.currentUser.privileges.includes(privilege) + return this.$store.state.users.currentUser.privileges?.includes(privilege) }, toggleTag (tag) { const store = this.$store diff --git a/src/components/navigation/filter.js b/src/components/navigation/filter.js index 12ab9266e..8e5ace57b 100644 --- a/src/components/navigation/filter.js +++ b/src/components/navigation/filter.js @@ -19,11 +19,11 @@ export const getListEntries = store => store.allLists.map(list => ({ iconLetter: list.title[0] })) -export const getBookmarkFolderEntries = store => store.allFolders.map(folder => ({ +export const getBookmarkFolderEntries = store => store.allFolders ? store.allFolders.map(folder => ({ name: 'bookmark-folder-' + folder.id, routeObject: { name: 'bookmark-folder', params: { id: folder.id } }, labelRaw: folder.name, iconEmoji: folder.emoji, iconEmojiUrl: folder.emoji_url, iconLetter: folder.name[0] -})) +})) : [] diff --git a/src/components/settings_modal/tabs/notifications_tab.js b/src/components/settings_modal/tabs/notifications_tab.js index c53b5889d..76007773b 100644 --- a/src/components/settings_modal/tabs/notifications_tab.js +++ b/src/components/settings_modal/tabs/notifications_tab.js @@ -18,7 +18,7 @@ const NotificationsTab = { }, canReceiveReports () { if (!this.user) { return false } - return this.user.privileges.includes('reports_manage_reports') + return this.user.privileges?.includes('reports_manage_reports') }, ...SharedComputedObject() }, diff --git a/src/components/status_action_buttons/buttons_definitions.js b/src/components/status_action_buttons/buttons_definitions.js index bc1e45a98..4e07839a2 100644 --- a/src/components/status_action_buttons/buttons_definitions.js +++ b/src/components/status_action_buttons/buttons_definitions.js @@ -204,7 +204,7 @@ export const BUTTONS = [{ if ({ status, loggedIn, currentUser }) { return loggedIn && ( status.user.id === currentUser.id || - currentUser.privileges.includes('messages_delete') + currentUser.privileges?.includes('messages_delete') ) }, confirm: ({ getters }) => getters.mergedConfig.modalOnDelete, diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index be81b8ad5..634d48502 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -134,7 +134,10 @@ export default { }, showModerationMenu () { const privileges = this.loggedIn.privileges - return this.loggedIn.role === 'admin' || privileges.includes('users_manage_activation_state') || privileges.includes('users_delete') || privileges.includes('users_manage_tags') + return this.loggedIn.role === 'admin' || + privileges?.includes('users_manage_activation_state') || + privileges?.includes('users_delete')|| + privileges?.includes('users_manage_tags') }, hasNote () { return this.relationship.note diff --git a/src/modules/api.js b/src/modules/api.js index 69c8282b8..78f4e010c 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -281,6 +281,7 @@ const api = { // Bookmark folders startFetchingBookmarkFolders (store) { if (store.state.fetchers.bookmarkFolders) return + if (!store.rootState.instance.pleromaBookmarkFoldersAvailable) return const fetcher = store.state.backendInteractor.startFetchingBookmarkFolders({ store }) store.commit('addFetcher', { fetcherName: 'bookmarkFolders', fetcher }) }, diff --git a/src/modules/statuses.js b/src/modules/statuses.js index d08b3334c..8b09263e0 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -38,6 +38,7 @@ export const defaultState = () => ({ allStatusesObject: {}, conversationsObject: {}, maxId: 0, + scrobblesUnsupported: false, favorites: new Set(), timelines: { mentions: emptyTl(), @@ -112,8 +113,14 @@ const getLatestScrobble = (state, user) => { return } + if (state.scrobblesUnsupported) return + state.scrobblesNextFetch[user.id] = Date.now() + 24 * 60 * 60 * 1000 apiService.fetchScrobbles({ accountId: user.id }).then((scrobbles) => { + if (scrobbles?.error?.status === 501) { + state.scrobblesUnsupported = true + } + if (scrobbles.length > 0) { user.latestScrobble = scrobbles[0] diff --git a/src/modules/users.js b/src/modules/users.js index 01936c716..c59c04dff 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -599,6 +599,7 @@ const users = { return new Promise((resolve, reject) => { const commit = store.commit const dispatch = store.dispatch + const rootState = store.rootState commit('beginLogin') store.rootState.api.backendInteractor.verifyCredentials(accessToken) .then((data) => { @@ -665,8 +666,10 @@ const users = { // Start fetching notifications dispatch('startFetchingNotifications') - // Start fetching chats - dispatch('startFetchingChats') + if (rootState.instance.pleromaChatMessagesAvailable) { + // Start fetching chats + dispatch('startFetchingChats') + } } dispatch('startFetchingLists') diff --git a/src/stores/announcements.js b/src/stores/announcements.js index 5ee279835..02b5b7cdd 100644 --- a/src/stores/announcements.js +++ b/src/stores/announcements.js @@ -25,7 +25,7 @@ export const useAnnouncementsStore = defineStore('announcements', { } const currentUser = window.vuex.state.users.currentUser - const isAdmin = currentUser && currentUser.privileges.includes('announcements_manage_announcements') + const isAdmin = currentUser && currentUser.privileges?.includes('announcements_manage_announcements') const getAnnouncements = async () => { if (!isAdmin) { From ac8519c166da7939ff025145b106a68569d3ebef Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Jun 2025 15:31:21 +0300 Subject: [PATCH 02/22] Make public favorites optional (Akkoma/Sharkey.NET?) --- src/components/user_profile/user_profile.js | 2 +- src/modules/instance.js | 1 + src/services/timeline_fetcher/timeline_fetcher.service.js | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 751bfd5a0..49d6fd60a 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -81,7 +81,7 @@ const UserProfile = { return this.isUs || !this.user.hide_followers }, favoritesTabVisible () { - return this.isUs || !this.user.hide_favorites + return this.isUs || (this.$store.state.instance.pleromaPublicFavouritesAvailable && !this.user.hide_favorites) }, formattedBirthday () { const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale) diff --git a/src/modules/instance.js b/src/modules/instance.js index 83671a881..5074165f9 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -156,6 +156,7 @@ const defaultState = { pleromaChatMessagesAvailable: false, pleromaCustomEmojiReactionsAvailable: false, pleromaBookmarkFoldersAvailable: false, + pleromaPublicFavouritesAvailable: true, gopherAvailable: false, mediaProxyAvailable: false, suggestionsEnabled: false, diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js index d85fc7305..fdf235af7 100644 --- a/src/services/timeline_fetcher/timeline_fetcher.service.js +++ b/src/services/timeline_fetcher/timeline_fetcher.service.js @@ -63,6 +63,10 @@ const fetchAndUpdate = ({ return apiService.fetchTimeline(args) .then(response => { if (response.errors) { + if (timeline === 'favorites') { + rootState.instance.pleromaPublicFavouritesAvailable = false + return + } throw new Error(`${response.status} ${response.statusText}`) } From b5fd56c7909ae40bf7ef7a7a0d6fa1522040b15e Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Jun 2025 15:31:43 +0300 Subject: [PATCH 03/22] scrobbles --- src/modules/statuses.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 8b09263e0..fc922337e 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -38,8 +38,8 @@ export const defaultState = () => ({ allStatusesObject: {}, conversationsObject: {}, maxId: 0, - scrobblesUnsupported: false, favorites: new Set(), + pleromaScrobblesAvailable: true, // not reported in nodeinfo timelines: { mentions: emptyTl(), public: emptyTl(), @@ -109,16 +109,19 @@ const sortTimeline = (timeline) => { } const getLatestScrobble = (state, user) => { + const scrobbles = state.pleromaScrobblesAvailable + if (!scrobbles) return + if (state.scrobblesNextFetch[user.id] && state.scrobblesNextFetch[user.id] > Date.now()) { return } - if (state.scrobblesUnsupported) return - state.scrobblesNextFetch[user.id] = Date.now() + 24 * 60 * 60 * 1000 + if (!scrobbles) return apiService.fetchScrobbles({ accountId: user.id }).then((scrobbles) => { if (scrobbles?.error?.status === 501) { - state.scrobblesUnsupported = true + state.pleromaScrobblesAvailable = false + return } if (scrobbles.length > 0) { From 77a2457f09d37ed57732b3df09fe61178419d199 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Jun 2025 15:34:55 +0300 Subject: [PATCH 04/22] changelog --- changelog.d/akkoma-sharkey-net-support.add | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/akkoma-sharkey-net-support.add diff --git a/changelog.d/akkoma-sharkey-net-support.add b/changelog.d/akkoma-sharkey-net-support.add new file mode 100644 index 000000000..0e39a4145 --- /dev/null +++ b/changelog.d/akkoma-sharkey-net-support.add @@ -0,0 +1 @@ +Added support for Akkoma and Sharkey.NET backend (tested on Sharkey) From 30152e3780a3c4edbe4ff927237d13c100bcb0c1 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 16 Jun 2025 16:25:49 +0300 Subject: [PATCH 05/22] fix quotes --- .../entity_normalizer.service.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index d9e3d427a..6d9afdc96 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -317,20 +317,18 @@ export const parseStatus = (data) => { output.edited_at = data.edited_at + const { pleroma } = data + if (data.pleroma) { - const { pleroma } = data output.text = pleroma.content ? data.pleroma.content['text/plain'] : data.content output.summary = pleroma.spoiler_text ? data.pleroma.spoiler_text['text/plain'] : data.spoiler_text output.statusnet_conversation_id = data.pleroma.conversation_id output.is_local = pleroma.local - output.in_reply_to_screen_name = data.pleroma.in_reply_to_account_acct + output.in_reply_to_screen_name = pleroma.in_reply_to_account_acct output.thread_muted = pleroma.thread_muted output.emoji_reactions = pleroma.emoji_reactions output.parent_visible = pleroma.parent_visible === undefined ? true : pleroma.parent_visible - output.quote = pleroma.quote ? parseStatus(pleroma.quote) : undefined - output.quote_id = pleroma.quote_id ? pleroma.quote_id : (output.quote ? output.quote.id : undefined) - output.quote_url = pleroma.quote_url - output.quote_visible = pleroma.quote_visible + output.quote_visible = pleroma.quote_visible || true output.quotes_count = pleroma.quotes_count output.bookmark_folder_id = pleroma.bookmark_folder } else { @@ -338,6 +336,12 @@ export const parseStatus = (data) => { output.summary = data.spoiler_text } + const quoteRaw = pleroma?.quote || data.quote + const quoteData = quoteRaw ? parseStatus(quoteRaw) : undefined + output.quote = quoteData + output.quote_id = data.quote?.id ?? data.quote_id ?? quoteData?.id ?? pleroma.quote_id + output.quote_url = data.quote?.url ?? quoteData?.url ?? pleroma.quote_url + output.in_reply_to_status_id = data.in_reply_to_id output.in_reply_to_user_id = data.in_reply_to_account_id output.replies_count = data.replies_count From 21978806fbeca389a4ccf605250ecbaff1fea768 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 17 Jun 2025 09:37:10 +0300 Subject: [PATCH 06/22] admin api update --- src/services/api/api.service.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 117c621d9..ce424eab3 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -15,7 +15,7 @@ const TAG_USER_URL = '/api/pleroma/admin/users/tag' const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}` const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate' const DEACTIVATE_USER_URL = '/api/pleroma/admin/users/deactivate' -const ADMIN_USERS_URL = '/api/pleroma/admin/users' +const ADMIN_USERS_URL = '/api/v1/pleroma/admin/users' const SUGGESTIONS_URL = '/api/v1/suggestions' const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings' const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read' @@ -99,7 +99,7 @@ const PLEROMA_CHAT_URL = id => `/api/v1/pleroma/chats/by-account-id/${id}` const PLEROMA_CHAT_MESSAGES_URL = id => `/api/v1/pleroma/chats/${id}/messages` const PLEROMA_CHAT_READ_URL = id => `/api/v1/pleroma/chats/${id}/read` const PLEROMA_DELETE_CHAT_MESSAGE_URL = (chatId, messageId) => `/api/v1/pleroma/chats/${chatId}/messages/${messageId}` -const PLEROMA_ADMIN_REPORTS = '/api/pleroma/admin/reports' +const PLEROMA_ADMIN_REPORTS = '/api/v1/pleroma/admin/reports' const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups' const PLEROMA_ANNOUNCEMENTS_URL = '/api/v1/pleroma/admin/announcements' const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements' @@ -111,10 +111,10 @@ const PLEROMA_USER_FAVORITES_TIMELINE_URL = id => `/api/v1/pleroma/accounts/${id const PLEROMA_BOOKMARK_FOLDERS_URL = '/api/v1/pleroma/bookmark_folders' const PLEROMA_BOOKMARK_FOLDER_URL = id => `/api/v1/pleroma/bookmark_folders/${id}` -const PLEROMA_ADMIN_CONFIG_URL = '/api/pleroma/admin/config' -const PLEROMA_ADMIN_DESCRIPTIONS_URL = '/api/pleroma/admin/config/descriptions' -const PLEROMA_ADMIN_FRONTENDS_URL = '/api/pleroma/admin/frontends' -const PLEROMA_ADMIN_FRONTENDS_INSTALL_URL = '/api/pleroma/admin/frontends/install' +const PLEROMA_ADMIN_CONFIG_URL = '/api/v1/pleroma/admin/config' +const PLEROMA_ADMIN_DESCRIPTIONS_URL = '/api/v1/pleroma/admin/config/descriptions' +const PLEROMA_ADMIN_FRONTENDS_URL = '/api/v1/pleroma/admin/frontends' +const PLEROMA_ADMIN_FRONTENDS_INSTALL_URL = '/api/v1/pleroma/admin/frontends/install' const PLEROMA_EMOJI_RELOAD_URL = '/api/pleroma/admin/reload_emoji' const PLEROMA_EMOJI_IMPORT_FS_URL = '/api/pleroma/emoji/packs/import' From 78c92e15d6e5d595fce888d1fdb2c012b137cb0e Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 17 Jun 2025 09:37:19 +0300 Subject: [PATCH 07/22] public favorites check --- src/modules/api.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/api.js b/src/modules/api.js index 78f4e010c..ab8d7162f 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -211,6 +211,7 @@ const api = { statusId = false, bookmarkFolderId = false }) { + if (timeline === 'favourites' && !store.rootState.instance.pleromaPublicFavouritesAvailable) return if (store.state.fetchers[timeline]) return const fetcher = store.state.backendInteractor.startFetchingTimeline({ From 15a79c2a24028367c2553807021aa57867e279ce Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 17 Jun 2025 09:48:02 +0300 Subject: [PATCH 08/22] even if it's not really used anywhere it's a good idea to check it like that --- src/boot/after_store.js | 6 +++--- .../settings_modal/tabs/security_tab/security_tab.js | 4 ++-- src/modules/instance.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 42cd14b0a..7ce4959bf 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -63,10 +63,11 @@ const getInstanceConfig = async ({ store }) => { const textlimit = data.max_toot_chars const vapidPublicKey = data.pleroma.vapid_public_key + store.dispatch('setInstanceOption', { name: 'pleromaExtensionsAvailable', value: data.pleroma }) store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit }) store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required }) - store.dispatch('setInstanceOption', { name: 'birthdayRequired', value: !!data.pleroma.metadata.birthday_required }) - store.dispatch('setInstanceOption', { name: 'birthdayMinAge', value: data.pleroma.metadata.birthday_min_age || 0 }) + store.dispatch('setInstanceOption', { name: 'birthdayRequired', value: !!data.pleroma?.metadata.birthday_required }) + store.dispatch('setInstanceOption', { name: 'birthdayMinAge', value: data.pleroma?.metadata.birthday_min_age || 0 }) if (vapidPublicKey) { store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey }) @@ -281,7 +282,6 @@ const getNodeInfo = async ({ store }) => { const software = data.software store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version }) store.dispatch('setInstanceOption', { name: 'backendRepository', value: software.repository }) - store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' }) const priv = metadata.private store.dispatch('setInstanceOption', { name: 'private', value: priv }) diff --git a/src/components/settings_modal/tabs/security_tab/security_tab.js b/src/components/settings_modal/tabs/security_tab/security_tab.js index 3cbc0c927..04e0328cd 100644 --- a/src/components/settings_modal/tabs/security_tab/security_tab.js +++ b/src/components/settings_modal/tabs/security_tab/security_tab.js @@ -41,8 +41,8 @@ const SecurityTab = { user () { return this.$store.state.users.currentUser }, - pleromaBackend () { - return this.$store.state.instance.pleromaBackend + pleromaExtensionsAvailable () { + return this.$store.state.instance.pleromaExtensionsAvailable }, oauthTokens () { return useOAuthTokensStore().tokens.map(oauthToken => { diff --git a/src/modules/instance.js b/src/modules/instance.js index 5074165f9..033096edd 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -143,7 +143,7 @@ const defaultState = { emoji: {}, emojiFetched: false, unicodeEmojiAnnotations: {}, - pleromaBackend: true, + pleromaExtensionsAvailable: true, postFormats: [], restrictedNicknames: [], safeDM: true, From f965d874eeb0783343534380fffddf99768399a7 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 17 Jun 2025 09:54:58 +0300 Subject: [PATCH 09/22] excuses --- src/boot/after_store.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 7ce4959bf..cbacfcd0e 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -79,6 +79,8 @@ const getInstanceConfig = async ({ store }) => { console.error('Could not load instance config, potentially fatal') console.error(error) } + // We should check for scrobbles support here but it requires userId + // so instead we check for it where it's fetched (statuses.js) } const getBackendProvidedConfig = async () => { From 26b6f78f0bd27ed737f3f6f752c3029074823e6f Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 18 Jun 2025 16:58:11 +0300 Subject: [PATCH 10/22] emoji --- src/modules/instance.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/instance.js b/src/modules/instance.js index 033096edd..98917e791 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -341,7 +341,10 @@ const instance = { async getCustomEmoji ({ commit, state }) { try { - const res = await window.fetch('/api/pleroma/emoji.json') + let res = await window.fetch('/api/v1/pleroma/emoji') + if (!res.ok) { + res = await window.fetch('/api/pleroma/emoji.json') + } if (res.ok) { const result = await res.json() const values = Array.isArray(result) ? Object.assign({}, ...result) : result From 96c57a8adabd59b3fba3452da019a594b8830ae9 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 18 Jun 2025 17:48:11 +0300 Subject: [PATCH 11/22] bubble timeline --- src/boot/after_store.js | 1 + src/boot/routes.js | 2 ++ src/components/nav_panel/nav_panel.js | 11 ++++++++--- src/components/navigation/navigation.js | 6 ++++++ src/components/timeline_menu/timeline_menu.js | 9 ++++++--- src/i18n/en.json | 1 + src/modules/statuses.js | 3 ++- src/services/api/api.service.js | 4 +++- .../timeline_fetcher/timeline_fetcher.service.js | 2 +- 9 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/boot/after_store.js b/src/boot/after_store.js index cbacfcd0e..39fc6f6f0 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -266,6 +266,7 @@ const getNodeInfo = async ({ store }) => { store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled }) store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') }) store.dispatch('setInstanceOption', { name: 'groupActorAvailable', value: features.includes('pleroma:group_actors') }) + store.dispatch('setInstanceOption', { name: 'localBubbleInstances', value: metadata.localBubbleInstances ?? [] }) const uploadLimits = metadata.uploadLimits store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) }) diff --git a/src/boot/routes.js b/src/boot/routes.js index da87c6c61..02abf8ce6 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -1,4 +1,5 @@ import PublicTimeline from 'components/public_timeline/public_timeline.vue' +import BubbleTimeline from 'components/bubble_timeline/bubble_timeline.vue' import PublicAndExternalTimeline from 'components/public_and_external_timeline/public_and_external_timeline.vue' import FriendsTimeline from 'components/friends_timeline/friends_timeline.vue' import TagTimeline from 'components/tag_timeline/tag_timeline.vue' @@ -54,6 +55,7 @@ export default (store) => { { name: 'friends', path: '/main/friends', component: FriendsTimeline, beforeEnter: validateAuthenticatedRoute }, { name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline }, { name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline }, + { name: 'bubble', path: '/bubble', component: BubbleTimeline }, { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, { name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline }, { diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js index 681aaf05b..2cdb4c45b 100644 --- a/src/components/nav_panel/nav_panel.js +++ b/src/components/nav_panel/nav_panel.js @@ -15,6 +15,7 @@ import { library } from '@fortawesome/fontawesome-svg-core' import { faUsers, faGlobe, + faCity, faBookmark, faEnvelope, faChevronDown, @@ -31,6 +32,7 @@ import { library.add( faUsers, faGlobe, + faCity, faBookmark, faEnvelope, faChevronDown, @@ -108,7 +110,8 @@ const NavPanel = { privateMode: state => state.instance.private, federating: state => state.instance.federating, pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable, - bookmarkFolders: state => state.instance.pleromaBookmarkFoldersAvailable + bookmarkFolders: state => state.instance.pleromaBookmarkFoldersAvailable, + bubbleTimeline: state => state.instance.localBubbleInstances.length > 0 }), timelinesItems () { return filterNavigation( @@ -121,7 +124,8 @@ const NavPanel = { isFederating: this.federating, isPrivate: this.privateMode, currentUser: this.currentUser, - supportsBookmarkFolders: this.bookmarkFolders + supportsBookmarkFolders: this.bookmarkFolders, + supportsBubbleTimeline: this.bubbleTimeline } ) }, @@ -136,7 +140,8 @@ const NavPanel = { isFederating: this.federating, isPrivate: this.privateMode, currentUser: this.currentUser, - supportsBookmarkFolders: this.bookmarkFolders + supportsBookmarkFolders: this.bookmarkFolders, + supportsBubbleTimeline: this.bubbleTimeline } ) }, diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js index a8e1fc966..6702bea4e 100644 --- a/src/components/navigation/navigation.js +++ b/src/components/navigation/navigation.js @@ -27,6 +27,12 @@ export const TIMELINES = { label: 'nav.public_tl', criteria: ['!private'] }, + bubble: { + route: 'bubble', + icon: 'city', + label: 'nav.bubble', + criteria: ['supportsBubbleTimeline'] + }, twkn: { route: 'public-external-timeline', anon: true, diff --git a/src/components/timeline_menu/timeline_menu.js b/src/components/timeline_menu/timeline_menu.js index 38e6bdf4f..4c8f7b76e 100644 --- a/src/components/timeline_menu/timeline_menu.js +++ b/src/components/timeline_menu/timeline_menu.js @@ -24,7 +24,8 @@ export const timelineNames = (supportsBookmarkFolders) => { dms: 'nav.dms', 'public-timeline': 'nav.public_tl', 'public-external-timeline': 'nav.twkn', - quotes: 'nav.quotes' + quotes: 'nav.quotes', + bubble: 'nav.bubble' } } @@ -58,7 +59,8 @@ const TimelineMenu = { currentUser: state => state.users.currentUser, privateMode: state => state.instance.private, federating: state => state.instance.federating, - bookmarkFolders: state => state.instance.pleromaBookmarkFoldersAvailable + bookmarkFolders: state => state.instance.pleromaBookmarkFoldersAvailable, + bubbleTimeline: state => state.instance.localBubbleInstances.length > 0 }), timelinesList () { return filterNavigation( @@ -68,7 +70,8 @@ const TimelineMenu = { isFederating: this.federating, isPrivate: this.privateMode, currentUser: this.currentUser, - supportsBookmarkFolders: this.bookmarkFolders + supportsBookmarkFolders: this.bookmarkFolders, + supportsBubbleTimeline: this.bubbleTimeline } ) } diff --git a/src/i18n/en.json b/src/i18n/en.json index 019beba1c..5e99cc6ef 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -171,6 +171,7 @@ "interactions": "Interactions", "dms": "Direct messages", "public_tl": "Public timeline", + "bubble": "Bubble timeline", "timeline": "Timeline", "home_timeline": "Home timeline", "twkn": "Known Network", diff --git a/src/modules/statuses.js b/src/modules/statuses.js index fc922337e..efdfc5894 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -51,7 +51,8 @@ export const defaultState = () => ({ tag: emptyTl(), dms: emptyTl(), bookmarks: emptyTl(), - list: emptyTl() + list: emptyTl(), + bubble: emptyTl() } }) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index ce424eab3..6de94278e 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -61,6 +61,7 @@ const MASTODON_LIST_TIMELINE_URL = id => `/api/v1/timelines/list/${id}` const MASTODON_LIST_ACCOUNTS_URL = id => `/api/v1/lists/${id}/accounts` const MASTODON_TAG_TIMELINE_URL = tag => `/api/v1/timelines/tag/${tag}` const MASTODON_BOOKMARK_TIMELINE_URL = '/api/v1/bookmarks' +const AKKOMA_BUBBLE_TIMELINE_URL = '/api/v1/timelines/bubble' const MASTODON_USER_BLOCKS_URL = '/api/v1/blocks/' const MASTODON_USER_MUTES_URL = '/api/v1/mutes/' const MASTODON_BLOCK_USER_URL = id => `/api/v1/accounts/${id}/block` @@ -707,7 +708,8 @@ const fetchTimeline = ({ publicFavorites: PLEROMA_USER_FAVORITES_TIMELINE_URL, tag: MASTODON_TAG_TIMELINE_URL, bookmarks: MASTODON_BOOKMARK_TIMELINE_URL, - quotes: PLEROMA_STATUS_QUOTES_URL + quotes: PLEROMA_STATUS_QUOTES_URL, + bubble: AKKOMA_BUBBLE_TIMELINE_URL } const isNotifications = timeline === 'notifications' const params = [] diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js index fdf235af7..f64646593 100644 --- a/src/services/timeline_fetcher/timeline_fetcher.service.js +++ b/src/services/timeline_fetcher/timeline_fetcher.service.js @@ -54,7 +54,7 @@ const fetchAndUpdate = ({ args.bookmarkFolderId = bookmarkFolderId args.tag = tag args.withMuted = !hideMutedPosts - if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) { + if (loggedIn && ['friends', 'public', 'publicAndExternal', 'bubble'].includes(timeline)) { args.replyVisibility = replyVisibility } From 70c89b0cb9c6c16c190f2c9991c340559579cf8b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 18 Jun 2025 17:49:22 +0300 Subject: [PATCH 12/22] better approach to missing privileges --- src/components/announcement/announcement.js | 2 +- src/components/interactions/interactions.js | 2 +- src/components/moderation_tools/moderation_tools.js | 2 +- src/components/status_action_buttons/buttons_definitions.js | 2 +- src/components/user_card/user_card.js | 6 +++--- src/services/entity_normalizer/entity_normalizer.service.js | 2 +- src/stores/announcements.js | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/announcement/announcement.js b/src/components/announcement/announcement.js index a1b20bf60..d1b8257d8 100644 --- a/src/components/announcement/announcement.js +++ b/src/components/announcement/announcement.js @@ -29,7 +29,7 @@ const Announcement = { currentUser: state => state.users.currentUser }), canEditAnnouncement () { - return this.currentUser && this.currentUser.privileges?.includes('announcements_manage_announcements') + return this.currentUser && this.currentUser.privileges.includes('announcements_manage_announcements') }, content () { return this.announcement.content diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js index 458dca859..fc441b908 100644 --- a/src/components/interactions/interactions.js +++ b/src/components/interactions/interactions.js @@ -16,7 +16,7 @@ const Interactions = { return { allowFollowingMove: this.$store.state.users.currentUser.allow_following_move, filterMode: tabModeDict.mentions, - canSeeReports: this.$store.state.users.currentUser.privileges?.includes('reports_manage_reports') + canSeeReports: this.$store.state.users.currentUser.privileges.includes('reports_manage_reports') } }, methods: { diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js index a0c5884d4..bd57a353a 100644 --- a/src/components/moderation_tools/moderation_tools.js +++ b/src/components/moderation_tools/moderation_tools.js @@ -59,7 +59,7 @@ const ModerationTools = { return this.tagsSet.has(tagName) }, privileged (privilege) { - return this.$store.state.users.currentUser.privileges?.includes(privilege) + return this.$store.state.users.currentUser.privileges.includes(privilege) }, toggleTag (tag) { const store = this.$store diff --git a/src/components/status_action_buttons/buttons_definitions.js b/src/components/status_action_buttons/buttons_definitions.js index 4e07839a2..bc1e45a98 100644 --- a/src/components/status_action_buttons/buttons_definitions.js +++ b/src/components/status_action_buttons/buttons_definitions.js @@ -204,7 +204,7 @@ export const BUTTONS = [{ if ({ status, loggedIn, currentUser }) { return loggedIn && ( status.user.id === currentUser.id || - currentUser.privileges?.includes('messages_delete') + currentUser.privileges.includes('messages_delete') ) }, confirm: ({ getters }) => getters.mergedConfig.modalOnDelete, diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index 634d48502..f4ae5f12e 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -135,9 +135,9 @@ export default { showModerationMenu () { const privileges = this.loggedIn.privileges return this.loggedIn.role === 'admin' || - privileges?.includes('users_manage_activation_state') || - privileges?.includes('users_delete')|| - privileges?.includes('users_manage_tags') + privileges.includes('users_manage_activation_state') || + privileges.includes('users_delete')|| + privileges.includes('users_manage_tags') }, hasNote () { return this.relationship.note diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 6d9afdc96..99ad2b30a 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -129,7 +129,7 @@ export const parseUser = (data) => { output.birthday = data.pleroma.birthday if (data.pleroma.privileges) { - output.privileges = data.pleroma.privileges + output.privileges = data.pleroma.privileges ?? [] } else if (data.pleroma.is_admin) { output.privileges = [ 'users_read', diff --git a/src/stores/announcements.js b/src/stores/announcements.js index 02b5b7cdd..5ee279835 100644 --- a/src/stores/announcements.js +++ b/src/stores/announcements.js @@ -25,7 +25,7 @@ export const useAnnouncementsStore = defineStore('announcements', { } const currentUser = window.vuex.state.users.currentUser - const isAdmin = currentUser && currentUser.privileges?.includes('announcements_manage_announcements') + const isAdmin = currentUser && currentUser.privileges.includes('announcements_manage_announcements') const getAnnouncements = async () => { if (!isAdmin) { From 4c3626574d9029d47d506cb1f6d68e0d7ba21123 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 18 Jun 2025 17:49:40 +0300 Subject: [PATCH 13/22] support displaying of echo chamber status visibility --- src/components/status/status.js | 4 ++++ src/i18n/en.json | 1 + 2 files changed, 5 insertions(+) diff --git a/src/components/status/status.js b/src/components/status/status.js index 7ee2632bd..ba6fe1b68 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -24,6 +24,7 @@ import { faLock, faLockOpen, faGlobe, + faIgloo, faTimes, faRetweet, faReply, @@ -43,6 +44,7 @@ import { library.add( faEnvelope, faGlobe, + faIgloo, faLock, faLockOpen, faTimes, @@ -484,6 +486,8 @@ const Status = { return 'lock-open' case 'direct': return 'envelope' + case 'local': + return 'igloo' default: return 'globe' } diff --git a/src/i18n/en.json b/src/i18n/en.json index 5e99cc6ef..9f52d7bd1 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -117,6 +117,7 @@ "flash_security": "Note that this can be potentially dangerous since Flash content is still arbitrary code.", "flash_fail": "Failed to load flash content, see console for details.", "scope_in_timeline": { + "local": "Non-federated", "direct": "Direct", "private": "Followers-only", "public": "Public", From feb630ef1fbcfea0034f02c18472dfb082c7f784 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 18 Jun 2025 17:55:08 +0300 Subject: [PATCH 14/22] forgotten files --- .../bubble_timeline/bubble_timeline.js | 18 ++++++++++++++++++ .../bubble_timeline/bubble_timeline.vue | 9 +++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/components/bubble_timeline/bubble_timeline.js create mode 100644 src/components/bubble_timeline/bubble_timeline.vue diff --git a/src/components/bubble_timeline/bubble_timeline.js b/src/components/bubble_timeline/bubble_timeline.js new file mode 100644 index 000000000..6f73dd2b8 --- /dev/null +++ b/src/components/bubble_timeline/bubble_timeline.js @@ -0,0 +1,18 @@ +import Timeline from '../timeline/timeline.vue' +const BubbleTimeline = { + components: { + Timeline + }, + computed: { + timeline () { return this.$store.state.statuses.timelines.bubble } + }, + created () { + this.$store.dispatch('startFetchingTimeline', { timeline: 'bubble' }) + }, + unmounted () { + this.$store.dispatch('stopFetchingTimeline', 'bubble') + } + +} + +export default BubbleTimeline diff --git a/src/components/bubble_timeline/bubble_timeline.vue b/src/components/bubble_timeline/bubble_timeline.vue new file mode 100644 index 000000000..4aefa2729 --- /dev/null +++ b/src/components/bubble_timeline/bubble_timeline.vue @@ -0,0 +1,9 @@ + + + From 2bf584b89f4bda5b508b1768720c270045d43da9 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Tue, 17 Jun 2025 08:13:03 +0500 Subject: [PATCH 15/22] i18n: add translation for Misskey Flavored Markdown --- src/i18n/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/en.json b/src/i18n/en.json index 9f52d7bd1..14f36844b 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -291,7 +291,8 @@ "text/plain": "Plain text", "text/html": "HTML", "text/markdown": "Markdown", - "text/bbcode": "BBCode" + "text/bbcode": "BBCode", + "text/x.misskeymarkdown": "MFM" }, "content_type_selection": "Post format", "content_warning": "Subject (optional)", From a171f5cbe7c526e26ba9b0918adeafa258b05397 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 18 Jun 2025 19:44:38 +0300 Subject: [PATCH 16/22] fix iceshrimp for real this time --- src/services/entity_normalizer/entity_normalizer.service.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 99ad2b30a..61eb5313f 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -91,6 +91,8 @@ export const parseUser = (data) => { output.bot = data.bot + output.privileges = [] + if (data.pleroma) { if (data.pleroma.settings_store) { output.storage = data.pleroma.settings_store['pleroma-fe'] @@ -129,7 +131,7 @@ export const parseUser = (data) => { output.birthday = data.pleroma.birthday if (data.pleroma.privileges) { - output.privileges = data.pleroma.privileges ?? [] + output.privileges = data.pleroma.privileges } else if (data.pleroma.is_admin) { output.privileges = [ 'users_read', From 645585b03305a0676d83162c3eee163bc45d0fb6 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 18 Jun 2025 19:53:36 +0300 Subject: [PATCH 17/22] bubble visibility --- src/components/navigation/filter.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/navigation/filter.js b/src/components/navigation/filter.js index 8e5ace57b..325bb5a43 100644 --- a/src/components/navigation/filter.js +++ b/src/components/navigation/filter.js @@ -1,4 +1,12 @@ -export const filterNavigation = (list = [], { hasChats, hasAnnouncements, isFederating, isPrivate, currentUser, supportsBookmarkFolders }) => { +export const filterNavigation = (list = [], { + hasChats, + hasAnnouncements, + isFederating, + isPrivate, + currentUser, + supportsBookmarkFolders, + supportsBubbleTimeline +}) => { return list.filter(({ criteria, anon, anonRoute }) => { const set = new Set(criteria || []) if (!isFederating && set.has('federating')) return false @@ -8,6 +16,7 @@ export const filterNavigation = (list = [], { hasChats, hasAnnouncements, isFede if (!hasChats && set.has('chats')) return false if (!hasAnnouncements && set.has('announcements')) return false if (supportsBookmarkFolders && set.has('!supportsBookmarkFolders')) return false + if (supportsBubbleTimeline && set.has('!supportsBubbleTimeline')) return false return true }) } From ad2689a5ebcfef6389eb2eb3a7ef45afc4b0412c Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 18 Jun 2025 19:55:43 +0300 Subject: [PATCH 18/22] clarity --- src/components/navigation/filter.js | 4 ++-- src/components/navigation/navigation.js | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/navigation/filter.js b/src/components/navigation/filter.js index 325bb5a43..69d0b43cb 100644 --- a/src/components/navigation/filter.js +++ b/src/components/navigation/filter.js @@ -15,8 +15,8 @@ export const filterNavigation = (list = [], { if ((!currentUser || !currentUser.locked) && set.has('lockedUser')) return false if (!hasChats && set.has('chats')) return false if (!hasAnnouncements && set.has('announcements')) return false - if (supportsBookmarkFolders && set.has('!supportsBookmarkFolders')) return false - if (supportsBubbleTimeline && set.has('!supportsBubbleTimeline')) return false + if (!supportsBookmarkFolders && set.has('supportsBookmarkFolders')) return false + if (!supportsBubbleTimeline && set.has('supportsBubbleTimeline')) return false return true }) } diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js index 6702bea4e..80da8f52d 100644 --- a/src/components/navigation/navigation.js +++ b/src/components/navigation/navigation.js @@ -29,9 +29,10 @@ export const TIMELINES = { }, bubble: { route: 'bubble', + anon: true, icon: 'city', label: 'nav.bubble', - criteria: ['supportsBubbleTimeline'] + criteria: ['!private', 'federating', 'supportsBubbleTimeline'] }, twkn: { route: 'public-external-timeline', @@ -44,7 +45,7 @@ export const TIMELINES = { route: 'bookmarks', icon: 'bookmark', label: 'nav.bookmarks', - criteria: ['!supportsBookmarkFolders'] + criteria: ['supportsBookmarkFolders'] }, favorites: { routeObject: { name: 'user-profile', query: { tab: 'favorites' } }, From f0b1255a3cd2672df06cf7d05561c2aefe8f65e3 Mon Sep 17 00:00:00 2001 From: HJ <30-hj@users.noreply.git.pleroma.social> Date: Wed, 18 Jun 2025 18:46:33 +0000 Subject: [PATCH 19/22] Apply 2 suggestion(s) to 2 file(s) --- src/components/settings_modal/tabs/notifications_tab.js | 2 +- src/components/user_card/user_card.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/settings_modal/tabs/notifications_tab.js b/src/components/settings_modal/tabs/notifications_tab.js index 76007773b..c53b5889d 100644 --- a/src/components/settings_modal/tabs/notifications_tab.js +++ b/src/components/settings_modal/tabs/notifications_tab.js @@ -18,7 +18,7 @@ const NotificationsTab = { }, canReceiveReports () { if (!this.user) { return false } - return this.user.privileges?.includes('reports_manage_reports') + return this.user.privileges.includes('reports_manage_reports') }, ...SharedComputedObject() }, diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index f4ae5f12e..55c76225c 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -136,7 +136,7 @@ export default { const privileges = this.loggedIn.privileges return this.loggedIn.role === 'admin' || privileges.includes('users_manage_activation_state') || - privileges.includes('users_delete')|| + privileges.includes('users_delete') || privileges.includes('users_manage_tags') }, hasNote () { From 97497b59457265110f47d9ee3433c352dbc3cb81 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 24 Jun 2025 15:56:08 +0300 Subject: [PATCH 20/22] bubble pin --- src/components/navigation/navigation_pins.js | 9 +++++++-- src/modules/instance.js | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/navigation/navigation_pins.js b/src/components/navigation/navigation_pins.js index 50acbbaf1..2d1922acb 100644 --- a/src/components/navigation/navigation_pins.js +++ b/src/components/navigation/navigation_pins.js @@ -9,6 +9,7 @@ import { library } from '@fortawesome/fontawesome-svg-core' import { faUsers, faGlobe, + faCity, faBookmark, faEnvelope, faComments, @@ -25,6 +26,7 @@ import { useServerSideStorageStore } from 'src/stores/serverSideStorage' library.add( faUsers, faGlobe, + faCity, faBookmark, faEnvelope, faComments, @@ -65,7 +67,8 @@ const NavPanel = { followRequestCount: state => state.api.followRequests.length, privateMode: state => state.instance.private, federating: state => state.instance.federating, - pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable + pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable, + bubbleTimeline: state => state.instance.localBubbleInstances.length > 0 }), pinnedList () { if (!this.currentUser) { @@ -79,7 +82,8 @@ const NavPanel = { hasAnnouncements: this.supportsAnnouncements, isFederating: this.federating, isPrivate: this.privateMode, - currentUser: this.currentUser + currentUser: this.currentUser, + supportsBubbleTimeline: this.bubbleTimeline, }) } return filterNavigation( @@ -98,6 +102,7 @@ const NavPanel = { { hasChats: this.pleromaChatMessagesAvailable, hasAnnouncements: this.supportsAnnouncements, + supportsBubbleTimeline: this.bubbleTimeline, isFederating: this.federating, isPrivate: this.privateMode, currentUser: this.currentUser diff --git a/src/modules/instance.js b/src/modules/instance.js index 98917e791..39d1fc662 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -163,6 +163,7 @@ const defaultState = { suggestionsWeb: '', quotingAvailable: false, groupActorAvailable: false, + localBubbleInstances: [], // Akkoma // Html stuff instanceSpecificPanelContent: '', From 187d43a4e57147b856f21a173d0f10f7a9b8159b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 24 Jun 2025 17:01:17 +0300 Subject: [PATCH 21/22] better handling of bookmarks --- src/components/nav_panel/nav_panel.js | 7 ++++--- src/components/navigation/filter.js | 3 ++- src/components/navigation/navigation.js | 11 ++++++++++- src/components/navigation/navigation_pins.js | 2 ++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js index 2cdb4c45b..70d378e86 100644 --- a/src/components/nav_panel/nav_panel.js +++ b/src/components/nav_panel/nav_panel.js @@ -117,6 +117,8 @@ const NavPanel = { return filterNavigation( Object .entries({ ...TIMELINES }) + // do not show in timeliens list since it's in a better place now + .filter(([key]) => key !== 'bookmarks') .map(([k, v]) => ({ ...v, name: k })), { hasChats: this.pleromaChatMessagesAvailable, @@ -124,7 +126,6 @@ const NavPanel = { isFederating: this.federating, isPrivate: this.privateMode, currentUser: this.currentUser, - supportsBookmarkFolders: this.bookmarkFolders, supportsBubbleTimeline: this.bubbleTimeline } ) @@ -140,8 +141,8 @@ const NavPanel = { isFederating: this.federating, isPrivate: this.privateMode, currentUser: this.currentUser, - supportsBookmarkFolders: this.bookmarkFolders, - supportsBubbleTimeline: this.bubbleTimeline + supportsBubbleTimeline: this.bubbleTimeline, + supportsBookmarkFolders: this.bookmarkFolders } ) }, diff --git a/src/components/navigation/filter.js b/src/components/navigation/filter.js index 69d0b43cb..54abb67b4 100644 --- a/src/components/navigation/filter.js +++ b/src/components/navigation/filter.js @@ -15,8 +15,9 @@ export const filterNavigation = (list = [], { if ((!currentUser || !currentUser.locked) && set.has('lockedUser')) return false if (!hasChats && set.has('chats')) return false if (!hasAnnouncements && set.has('announcements')) return false - if (!supportsBookmarkFolders && set.has('supportsBookmarkFolders')) return false if (!supportsBubbleTimeline && set.has('supportsBubbleTimeline')) return false + if (!supportsBookmarkFolders && set.has('supportsBookmarkFolders')) return false + if (supportsBookmarkFolders && set.has('!supportsBookmarkFolders')) return false return true }) } diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js index 80da8f52d..d1c2b6763 100644 --- a/src/components/navigation/navigation.js +++ b/src/components/navigation/navigation.js @@ -41,11 +41,11 @@ export const TIMELINES = { label: 'nav.twkn', criteria: ['!private', 'federating'] }, + // bookmarks are still technically a timeline so we should show it in the dropdown bookmarks: { route: 'bookmarks', icon: 'bookmark', label: 'nav.bookmarks', - criteria: ['supportsBookmarkFolders'] }, favorites: { routeObject: { name: 'user-profile', query: { tab: 'favorites' } }, @@ -60,6 +60,15 @@ export const TIMELINES = { } export const ROOT_ITEMS = { + bookmarks: { + route: 'bookmarks', + icon: 'bookmark', + label: 'nav.bookmarks', + // shows bookmarks entry in a better suited location + // hides it when bookmark folders are supported since + // we show custom component instead of it + criteria: ['!supportsBookmarkFolders'] + }, interactions: { route: 'interactions', icon: 'bell', diff --git a/src/components/navigation/navigation_pins.js b/src/components/navigation/navigation_pins.js index 2d1922acb..f9a900fc6 100644 --- a/src/components/navigation/navigation_pins.js +++ b/src/components/navigation/navigation_pins.js @@ -84,6 +84,7 @@ const NavPanel = { isPrivate: this.privateMode, currentUser: this.currentUser, supportsBubbleTimeline: this.bubbleTimeline, + supportsBookmarkFolders: this.bookmarks }) } return filterNavigation( @@ -103,6 +104,7 @@ const NavPanel = { hasChats: this.pleromaChatMessagesAvailable, hasAnnouncements: this.supportsAnnouncements, supportsBubbleTimeline: this.bubbleTimeline, + supportsBookmarkFolders: this.bookmarks, isFederating: this.federating, isPrivate: this.privateMode, currentUser: this.currentUser From acd43a8593db3969f78f65f1b23e1c68868bde78 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 24 Jun 2025 17:15:00 +0300 Subject: [PATCH 22/22] oops --- src/components/nav_panel/nav_panel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js index 70d378e86..a155abe0c 100644 --- a/src/components/nav_panel/nav_panel.js +++ b/src/components/nav_panel/nav_panel.js @@ -126,7 +126,8 @@ const NavPanel = { isFederating: this.federating, isPrivate: this.privateMode, currentUser: this.currentUser, - supportsBubbleTimeline: this.bubbleTimeline + supportsBubbleTimeline: this.bubbleTimeline, + supportsBookmarkFolders: this.bookmarkFolders } ) },