diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index e2946b162..000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,223 +0,0 @@ -# This file is a template, and might need editing before it works on your project. -# Official framework image. Look for the different tagged releases at: -# https://hub.docker.com/r/library/node/tags/ -image: node:20 - -stages: - - check-changelog - - lint - - build - - test - - deploy - -# https://git.pleroma.social/help/ci/yaml/workflow.md#switch-between-branch-pipelines-and-merge-request-pipelines -workflow: - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS - when: never - - if: $CI_COMMIT_BRANCH - -check-changelog: - stage: check-changelog - image: alpine - rules: - - if: $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == 'pleroma/pleroma-fe' && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^renovate/ - when: never - - if: $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == 'pleroma/pleroma-fe' && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == 'weblate' - when: never - - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" - before_script: '' - after_script: '' - cache: {} - script: - - apk add git - - sh ./tools/check-changelog - -lint-eslint: - stage: lint - script: - - yarn - - yarn ci-eslint - -lint-biome: - stage: lint - script: - - yarn - - yarn ci-biome - -lint-stylelint: - stage: lint - script: - - yarn - - yarn ci-stylelint - -test: - stage: test - tags: - - amd64 - - himem - variables: - APT_CACHE_DIR: apt-cache - script: - - mkdir -pv $APT_CACHE_DIR && apt-get -qq update - - yarn - - yarn playwright install firefox - - yarn playwright install-deps - - yarn unit-ci - artifacts: - # When the test fails, upload screenshots for better context on why it fails - paths: - - test/**/__screenshots__ - when: on_failure - -e2e-pleroma: - stage: test - image: mcr.microsoft.com/playwright:v1.61.0-jammy - services: - - name: postgres:15-alpine - alias: db - - name: $PLEROMA_IMAGE - alias: pleroma - entrypoint: ["/bin/ash", "-c"] - command: - - | - set -eu - - SEED_SENTINEL_PATH=/var/lib/pleroma/.e2e_seeded - CONFIG_OVERRIDE_PATH=/var/lib/pleroma/config.exs - - echo '-- Waiting for database...' - while ! pg_isready -U ${DB_USER:-pleroma} -d postgres://${DB_HOST:-db}:${DB_PORT:-5432}/${DB_NAME:-pleroma} -t 1; do - sleep 1s - done - - echo '-- Writing E2E config overrides...' - cat > $CONFIG_OVERRIDE_PATH </dev/null; then - kill -TERM $PLEROMA_PID - wait $PLEROMA_PID || true - fi - } - - trap cleanup INT TERM - - echo '-- Waiting for API...' - api_ok=false - for _i in $(seq 1 120); do - if wget -qO- http://127.0.0.1:4000/api/v1/instance >/dev/null 2>&1; then - api_ok=true - break - fi - sleep 1s - done - - if [ $api_ok != true ]; then - echo 'Timed out waiting for Pleroma API to become available' - exit 1 - fi - - if [ ! -f $SEED_SENTINEL_PATH ]; then - if [ -n ${E2E_ADMIN_USERNAME:-} ] && [ -n ${E2E_ADMIN_PASSWORD:-} ] && [ -n ${E2E_ADMIN_EMAIL:-} ]; then - echo '-- Seeding admin user' $E2E_ADMIN_USERNAME '...' - if ! /opt/pleroma/bin/pleroma_ctl user new $E2E_ADMIN_USERNAME $E2E_ADMIN_EMAIL --admin --password $E2E_ADMIN_PASSWORD -y; then - echo '-- User already exists or creation failed, ensuring admin + confirmed...' - /opt/pleroma/bin/pleroma_ctl user set $E2E_ADMIN_USERNAME --admin --confirmed - fi - else - echo '-- Skipping admin seeding (missing E2E_ADMIN_* env)' - fi - - touch $SEED_SENTINEL_PATH - fi - - wait $PLEROMA_PID - tags: - - amd64 - - himem - variables: - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" - FF_NETWORK_PER_BUILD: "true" - PLEROMA_IMAGE: git.pleroma.social/pleroma/pleroma:stable - POSTGRES_USER: pleroma - POSTGRES_PASSWORD: pleroma - POSTGRES_DB: pleroma - DB_USER: pleroma - DB_PASS: pleroma - DB_NAME: pleroma - DB_HOST: db - DB_PORT: 5432 - DOMAIN: localhost - INSTANCE_NAME: Pleroma E2E - E2E_ADMIN_USERNAME: admin - E2E_ADMIN_PASSWORD: adminadmin - E2E_ADMIN_EMAIL: admin@example.com - ADMIN_EMAIL: $E2E_ADMIN_EMAIL - NOTIFY_EMAIL: $E2E_ADMIN_EMAIL - VITE_PROXY_TARGET: http://pleroma:4000 - VITE_PROXY_ORIGIN: http://localhost:4000 - E2E_BASE_URL: http://localhost:8099 - script: - - npm install -g yarn@1.22.22 - - yarn --frozen-lockfile - - | - echo "-- Waiting for Pleroma API..." - api_ok="false" - for _i in $(seq 1 120); do - if wget -qO- http://pleroma:4000/api/v1/instance >/dev/null 2>&1; then - api_ok="true" - break - fi - sleep 1s - done - if [ "$api_ok" != "true" ]; then - echo "Timed out waiting for Pleroma API to become available" - exit 1 - fi - - yarn e2e:pw - artifacts: - when: on_failure - paths: - - test/e2e-playwright/test-results - - test/e2e-playwright/playwright-report - -build: - stage: build - tags: - - amd64 - - himem - script: - - yarn - - yarn build - artifacts: - paths: - - dist/ - -docs-deploy: - stage: deploy - image: alpine:latest - only: - - develop@pleroma/pleroma-fe - before_script: - - apk add curl - script: - - curl -X POST -F"token=$DOCS_PIPELINE_TRIGGER" -F'ref=master' https://git.pleroma.social/api/v4/projects/673/trigger/pipeline diff --git a/.woodpecker/build-package.yaml b/.woodpecker/build-package.yaml index d06a267cd..63aa80e0f 100644 --- a/.woodpecker/build-package.yaml +++ b/.woodpecker/build-package.yaml @@ -14,7 +14,7 @@ labels: steps: build: - image: docker.io/node:20-alpine + image: docker.io/node:26-alpine commands: - apk add --no-cache zip git - yarn --frozen-lockfile diff --git a/.woodpecker/build.yaml b/.woodpecker/build.yaml index d6bd36f3e..70fb8df75 100644 --- a/.woodpecker/build.yaml +++ b/.woodpecker/build.yaml @@ -11,7 +11,7 @@ labels: steps: build: - image: docker.io/node:20-alpine + image: docker.io/node:26-alpine commands: - yarn --frozen-lockfile - yarn build diff --git a/.woodpecker/lint.yaml b/.woodpecker/lint.yaml index 257887338..4433e1be8 100644 --- a/.woodpecker/lint.yaml +++ b/.woodpecker/lint.yaml @@ -9,7 +9,7 @@ when: steps: install-depends: image: &node-image - docker.io/node:20-alpine + docker.io/node:26-alpine commands: - yarn --frozen-lockfile diff --git a/docs/HACKING.md b/docs/HACKING.md index 88760b77a..8d3c09a0c 100644 --- a/docs/HACKING.md +++ b/docs/HACKING.md @@ -81,7 +81,7 @@ In 99% cases PleromaFE uses [MastoAPI](https://docs.joinmastodon.org/api/) with PleromaFE supports both formats by transforming them into internal format which is basically QvitterAPI one with some additions and renaming. All data is passed trough [Entity Normalizer](https://git.pleroma.social/pleroma/pleroma-fe/src/src/services/entity_normalizer/entity_normalizer.service.js) which can serve as a reference of API and what's actually used, it's also a host for all the hacks and data transformation. -For most part, PleromaFE tries to store all the info it can get in global vuex store - every user and post are passed trough updating mechanism where data is either added or merged with existing data, reactively updating the information throughout UI, so if in newest request user's post counter increased, it will be instantly updated in open user profile cards. This is also used to find users, posts and sometimes to build timelines and/or request parameters. +For most part, PleromaFE tries to store all the info it can get in global pinia store - every user and post are passed trough updating mechanism where data is either added or merged with existing data, reactively updating the information throughout UI, so if in newest request user's post counter increased, it will be instantly updated in open user profile cards. This is also used to find users, posts and sometimes to build timelines and/or request parameters. PleromaFE also tries to persist this store, however only stable data is stored, such as user authentication and preferences, user highlights. Persistence is performed by saving and loading chunk of vuex store in browser's LocalStorage/IndexedDB. diff --git a/eslint.config.mjs b/eslint.config.mjs index 417ff8cf3..4335b36d5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,29 +1,15 @@ -import js from '@eslint/js' import { defineConfig, globalIgnores } from 'eslint/config' import vue from 'eslint-plugin-vue' -import globals from 'globals' export default defineConfig([ ...vue.configs['flat/recommended'], globalIgnores(['**/*.js', 'build/', 'dist/', 'config/']), { files: ['src/**/*.vue'], - plugins: { js }, - extends: ['js/recommended'], languageOptions: { - ecmaVersion: 2024, - sourceType: 'module', - parserOptions: { parser: '@babel/eslint-parser', }, - globals: { - ...globals.browser, - ...globals.vitest, - ...globals.chai, - ...globals.commonjs, - ...globals.serviceworker, - }, }, rules: { diff --git a/package.json b/package.json index c10f86b84..3ba4c6c24 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "lint-fix": "yarn exec eslint -- --fix; yarn exec stylelint '**/*.scss' '**/*.vue' --fix; biome check --write" }, "dependencies": { - "@babel/runtime": "7.28.4", + "@babel/runtime": "^8.0.0", "@chenfengyuan/vue-qrcode": "2.0.0", "@fortawesome/fontawesome-svg-core": "7.1.0", "@fortawesome/free-regular-svg-icons": "7.1.0", @@ -38,79 +38,58 @@ "click-outside-vue3": "4.0.1", "cropperjs": "2.0.1", "escape-html": "1.0.3", - "globals": "^16.0.0", "hash-sum": "^2.0.0", "js-cookie": "3.0.5", "localforage": "1.10.0", + "lodash-es": "4.17.21", "parse-link-header": "2.0.0", "phoenix": "1.8.1", - "pinia": "^3.0.4", + "pinia": "4.0.3", "punycode.js": "2.3.1", "qrcode": "1.5.4", "querystring-es3": "0.2.1", - "url": "0.11.4", "utf8": "3.0.0", "uuid": "11.1.0", - "vue": "3.5.22", - "vue-i18n": "11", - "vue-router": "4.6.4", - "vue-virtual-scroller": "^2.0.0-beta.7", - "vuex": "4.1.0" + "vue": "3.5.42", + "vue-i18n": "11.4.0", + "vue-router": "5.3.1", + "vue-virtual-scroller": "^3.0.5" }, "devDependencies": { - "@babel/core": "7.28.5", - "@babel/eslint-parser": "7.28.5", - "@babel/plugin-transform-runtime": "7.28.5", - "@babel/preset-env": "7.28.5", - "@babel/register": "7.28.3", - "@biomejs/biome": "2.3.11", + "@babel/core": "^8.0.0", + "@babel/eslint-parser": "^8.0.0", + "@babel/plugin-transform-runtime": "^8.0.0", + "@babel/preset-env": "^8.0.0", + "@babel/register": "^8.0.0", + "@biomejs/biome": "2.5.11", "@pinia/testing": "1.0.3", "@ungap/event-target": "0.2.4", "@vitejs/devtools": "^0.3.1", - "@vitejs/plugin-vue": "^6.0.7", + "@vitejs/plugin-vue": "^6.0.8", "@vitejs/plugin-vue-jsx": "^5.1.5", - "@vitest/browser": "^4.1.7", - "@vitest/browser-playwright": "^4.1.7", - "@vitest/coverage-v8": "^4.1.10", - "@vitest/ui": "^4.1.7", - "@vue/babel-helper-vue-jsx-merge-props": "1.4.0", - "@vue/babel-plugin-jsx": "1.5.0", + "@vitest/browser": "^4.1.11", + "@vitest/browser-playwright": "^4.1.11", + "@vitest/coverage-v8": "^4.1.11", + "@vitest/ui": "^4.1.11", + "@vue/babel-plugin-jsx": "3.0.0", "@vue/compiler-sfc": "3.5.22", - "@vue/test-utils": "2.4.6", + "@vue/devtools-api": "^8.1.5", + "@vue/test-utils": "2.5.0", "autoprefixer": "10.4.21", - "chai": "5.3.3", "chalk": "5.6.2", - "chromedriver": "135.0.4", - "connect-history-api-fallback": "2.0.0", "cross-spawn": "7.0.6", - "custom-event-polyfill": "1.0.7", "eslint": "9.39.2", - "eslint-config-standard": "17.1.0", - "eslint-formatter-friendly": "7.0.0", - "eslint-plugin-import": "2.32.0", - "eslint-plugin-n": "17.23.1", - "eslint-plugin-promise": "7.2.1", "eslint-plugin-vue": "10.6.2", - "eventsource-polyfill": "0.9.6", - "express": "5.1.0", - "function-bind": "1.1.2", - "http-proxy-middleware": "3.0.5", "iso-639-1": "3.1.5", - "lodash-es": "4.17.21", "msw": "2.14.6", "nightwatch": "3.12.2", - "oxc": "^1.0.1", "playwright": "1.61.0", "postcss": "8.5.6", "postcss-html": "^1.5.0", "postcss-scss": "^4.0.6", "sass-embedded": "^1.100.0", "selenium-server": "3.141.59", - "semver": "7.7.3", "serve-static": "2.2.0", - "shelljs": "0.10.0", - "sinon": "20.0.0", - "sinon-chai": "4.0.1", "stylelint": "16.25.0", "stylelint-config-html": "^1.1.0", "stylelint-config-recommended": "^16.0.0", @@ -120,12 +99,13 @@ "vite": "^8.0.0", "vite-plugin-eslint2": "^5.1.0", "vite-plugin-stylelint": "^6.1.0", - "vitest": "^4.1.7", + "vite-plugin-vue-devtools": "^8.2.1", + "vitest": "^4.1.11", "vue-eslint-parser": "10.2.0" }, "type": "module", "engines": { - "node": ">= 16.0.0" + "node": ">= 26.0.0" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/src/api/user.js b/src/api/user.js index 430b2c895..d3a2a4a70 100644 --- a/src/api/user.js +++ b/src/api/user.js @@ -17,8 +17,11 @@ const CHANGE_EMAIL_URL = '/api/pleroma/change_email' const CHANGE_PASSWORD_URL = '/api/pleroma/change_password' const MOVE_ACCOUNT_URL = '/api/pleroma/move_account' const ALIASES_URL = '/api/pleroma/aliases' -const NOTIFICATION_SETTINGS_URL = ({ blockFromStrangers, hideNotificationContents }) => - `/api/pleroma/notification_settings${paramsString({ blockFromStrangers, hideNotificationContents })}` +const NOTIFICATION_SETTINGS_URL = ({ + blockFromStrangers, + hideNotificationContents, +}) => + `/api/pleroma/notification_settings${paramsString({ blockFromStrangers, hideNotificationContents })}` export const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read' const MFA_SETTINGS_URL = '/api/pleroma/accounts/mfa' diff --git a/src/components/chat_new/chat_new.js b/src/components/chat_new/chat_new.js index 4f015db6a..03960a287 100644 --- a/src/components/chat_new/chat_new.js +++ b/src/components/chat_new/chat_new.js @@ -71,7 +71,6 @@ const chatNew = { this.loading = true this.userIds = [] - this.$store useSearchStore() .search({ q: query, resolve: true, type: 'accounts' }) .then((data) => { diff --git a/src/components/draft/draft.js b/src/components/draft/draft.js index 1c7f419c6..6c7f38287 100644 --- a/src/components/draft/draft.js +++ b/src/components/draft/draft.js @@ -1,11 +1,10 @@ -import { cloneDeep } from 'lodash' import { defineAsyncComponent } from 'vue' import Gallery from 'src/components/gallery/gallery.vue' import PostStatusForm from 'src/components/post_status_form/post_status_form.vue' import StatusContent from 'src/components/status_content/status_content.vue' -import { useMergedConfigStore } from 'src/stores/merged_config.js' +import { useDraftsStore } from 'src/stores/drafts.js' import { useStatusesStore } from 'src/stores/statuses.js' import { library } from '@fortawesome/fontawesome-svg-core' @@ -33,7 +32,6 @@ const Draft = { }, data() { return { - referenceDraft: cloneDeep(this.draft), editing: false, showingConfirmDialog: false, } @@ -50,14 +48,6 @@ const Draft = { return {} } }, - safeToSave() { - return ( - this.draft.status || - this.draft.files?.length || - this.draft.hasPoll || - this.draft.hasQuote - ) - }, postStatusFormProps() { return { draftId: this.draft.id, @@ -69,18 +59,12 @@ const Draft = { ? useStatusesStore().allStatuses.get(this.draft.refId) : undefined }, - localCollapseSubjectDefault() { - return useMergedConfigStore().mergedConfig.collapseMessageWithSubject - }, }, watch: { editing(newVal) { if (newVal) return - if (this.safeToSave) { - this.$store.dispatch('addOrSaveDraft', { draft: this.draft }) - } else { - this.$store.dispatch('addOrSaveDraft', { draft: this.referenceDraft }) - } + // (Post|Edit)StatusForm handles draft saving + this.$refs.form.saveDraft() }, }, methods: { @@ -91,9 +75,11 @@ const Draft = { this.showingConfirmDialog = true }, doAbandon() { - this.$store.dispatch('abandonDraft', { id: this.draft.id }).then(() => { - this.hideConfirmDialog() - }) + useDraftsStore() + .abandonDraft(this.draft.id) + .then(() => { + this.hideConfirmDialog() + }) }, hideConfirmDialog() { this.showingConfirmDialog = false diff --git a/src/components/draft/draft.vue b/src/components/draft/draft.vue index e610f627b..5302a3ab3 100644 --- a/src/components/draft/draft.vue +++ b/src/components/draft/draft.vue @@ -67,11 +67,13 @@
diff --git a/src/components/drafts/drafts.js b/src/components/drafts/drafts.js index 3d93edb14..3a37c0862 100644 --- a/src/components/drafts/drafts.js +++ b/src/components/drafts/drafts.js @@ -3,6 +3,8 @@ import { defineAsyncComponent } from 'vue' import Draft from 'src/components/draft/draft.vue' import List from 'src/components/list/list.vue' +import { useDraftsStore } from 'src/stores/drafts.js' + const Drafts = { components: { Draft, @@ -18,7 +20,7 @@ const Drafts = { }, computed: { drafts() { - return this.$store.getters.draftsArray + return useDraftsStore().draftsArray }, }, methods: { @@ -26,8 +28,8 @@ const Drafts = { this.showingConfirmDialog = true }, doAbandonAll() { - this.$store - .dispatch('abandonAllDrafts') + useDraftsStore() + .abandonAllDrafts() .then(() => this.hideConfirmDialog()) }, hideConfirmDialog() { diff --git a/src/components/edit_status_form/edit_status_form.js b/src/components/edit_status_form/edit_status_form.js index f7fd3d04d..0121d4597 100644 --- a/src/components/edit_status_form/edit_status_form.js +++ b/src/components/edit_status_form/edit_status_form.js @@ -15,9 +15,11 @@ const EditStatusForm = { requestClose() { this.$refs.postStatusForm.requestClose() }, + saveDraft() { + this.$refs.postStatusForm.saveDraft() + }, doEditStatus({ status, spoilerText, sensitive, media, contentType, poll }) { const params = { - store: this.$store, statusId: this.params.statusId, status, spoilerText, diff --git a/src/components/extra_notifications/extra_notifications.js b/src/components/extra_notifications/extra_notifications.js index d20cbb67e..70583bd2f 100644 --- a/src/components/extra_notifications/extra_notifications.js +++ b/src/components/extra_notifications/extra_notifications.js @@ -30,7 +30,7 @@ const ExtraNotifications = { return ( this.mergedConfig.showExtraNotifications && this.mergedConfig.showAnnouncementsInExtraNotifications && - this.unreadAnnouncementCount + this.unreadAnnouncementsCount ) }, shouldShowFollowRequests() { @@ -56,7 +56,7 @@ const ExtraNotifications = { return useUsersStore().currentUser }, ...mapState(useAnnouncementsStore, { - unreadAnnouncementCount: 'unreadAnnouncementCount', + unreadAnnouncementsCount: 'unreadAnnouncementsCount', }), ...mapState(useMergedConfigStore, ['mergedConfig']), ...mapState(useChatsStore, ['unreadChatsCount']), diff --git a/src/components/extra_notifications/extra_notifications.vue b/src/components/extra_notifications/extra_notifications.vue index 329c5c1c3..6e21efcb2 100644 --- a/src/components/extra_notifications/extra_notifications.vue +++ b/src/components/extra_notifications/extra_notifications.vue @@ -31,7 +31,7 @@ class="fa-scale-110 icon" icon="bullhorn" /> - {{ $t('notifications.unread_announcements', { num: unreadAnnouncementCount }, unreadAnnouncementCount) }} + {{ $t('notifications.unread_announcements', { num: unreadAnnouncementsCount }, unreadAnnouncementsCount) }}
useInstanceStore().uploadlimit) { const filesize = fileSizeFormatService.fileSizeFormat(file.size) const allowedsize = fileSizeFormatService.fileSizeFormat( @@ -145,7 +144,7 @@ const mediaUpload = { self.$emit('uploading') self.uploadCount++ - statusPosterService.uploadMedia({ store, formData }).then( + statusPosterService.uploadMedia({ formData }).then( (fileData) => { self.$emit('uploaded', fileData) self.decreaseUploadCount() diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js index e7fe404e0..67e8c4418 100644 --- a/src/components/mobile_nav/mobile_nav.js +++ b/src/components/mobile_nav/mobile_nav.js @@ -70,7 +70,7 @@ const MobileNav = { countExtraNotifications( useMergedConfigStore().mergedConfig, useChatsStore().unreadChatsCount, - useAnnouncementsStore().unreadAnnouncementCount, + useAnnouncementsStore().unreadAnnouncementsCount, useFollowRequestsStore().followRequestsCount, ) ) @@ -96,7 +96,7 @@ const MobileNav = { closingDrawerMarksAsSeen() { return useMergedConfigStore().mergedConfig.closingDrawerMarksAsSeen }, - ...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']), + ...mapState(useAnnouncementsStore, ['unreadAnnouncementsCount']), ...mapState(useMergedConfigStore, { pinnedItems: (store) => new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'), diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue index 8cdb70a1a..336ad60a6 100644 --- a/src/components/mobile_nav/mobile_nav.vue +++ b/src/components/mobile_nav/mobile_nav.vue @@ -19,7 +19,7 @@ icon="bars" />
diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js index f5de8bb2c..e03a0c9d7 100644 --- a/src/components/nav_panel/nav_panel.js +++ b/src/components/nav_panel/nav_panel.js @@ -112,7 +112,7 @@ const NavPanel = { }, computed: { ...mapState(useAnnouncementsStore, { - unreadAnnouncementCount: 'unreadAnnouncementCount', + unreadAnnouncementsCount: 'unreadAnnouncementsCount', supportsAnnouncements: (store) => store.supportsAnnouncements, }), ...mapState(useInstanceCapabilitiesStore, [ diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js index 7a2e29646..7f4208162 100644 --- a/src/components/navigation/navigation.js +++ b/src/components/navigation/navigation.js @@ -76,7 +76,7 @@ export const ROOT_ITEMS = { icon: 'comments', label: 'nav.chats', badgeStyle: 'notification', - badgeGetter: 'unreadChatsCount', + badgeGetter: 'unreadChats', criteria: ['chats'], }, friendRequests: { @@ -85,7 +85,7 @@ export const ROOT_ITEMS = { label: 'nav.friend_requests', badgeStyle: 'notification', criteria: ['lockedUser'], - badgeGetter: 'followRequestsCount', + badgeGetter: 'followRequests', }, about: { route: 'about', @@ -99,7 +99,7 @@ export const ROOT_ITEMS = { label: 'nav.announcements', store: 'announcements', badgeStyle: 'notification', - badgeGetter: 'unreadAnnouncementCount', + badgeGetter: 'unreadAnnouncements', criteria: ['announcements'], }, drafts: { @@ -107,7 +107,7 @@ export const ROOT_ITEMS = { icon: 'file-pen', label: 'nav.drafts', badgeStyle: 'neutral', - badgeGetter: 'draftCount', + badgeGetter: 'drafts', }, } diff --git a/src/components/navigation/navigation_entry.js b/src/components/navigation/navigation_entry.js index 31bc28eb5..1a7832afe 100644 --- a/src/components/navigation/navigation_entry.js +++ b/src/components/navigation/navigation_entry.js @@ -1,9 +1,12 @@ -import { mapState, mapStores } from 'pinia' +import { mapState } from 'pinia' import { routeTo } from 'src/components/navigation/navigation.js' import OptionalRouterLink from 'src/components/optional_router_link/optional_router_link.vue' import { useAnnouncementsStore } from 'src/stores/announcements.js' +import { useChatsStore } from 'src/stores/chats.js' +import { useDraftsStore } from 'src/stores/drafts.js' +import { useFollowRequestsStore } from 'src/stores/follow_requests.js' import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useUsersStore } from 'src/stores/users.js' @@ -40,11 +43,19 @@ const NavigationEntry = { routeTo() { return routeTo(this.item, this.currentUser) }, - getters() { - return this.$store.getters + badges() { + return { + drafts: this.draftsCount, + unreadAnnouncements: this.unreadAnnouncementsCount, + followRequests: this.followRequestsCount, + unreadChats: this.unreadChatsCount, + } }, - ...mapStores(useAnnouncementsStore), + ...mapState(useAnnouncementsStore, ['unreadAnnouncementsCount']), + ...mapState(useDraftsStore, ['draftsCount']), ...mapState(useUsersStore, ['currentUser']), + ...mapState(useChatsStore, ['unreadChatsCount']), + ...mapState(useFollowRequestsStore, ['followRequestsCount']), ...mapState(useSyncConfigStore, { pinnedItems: (store) => new Set(store.prefsStorage.collections.pinnedNavItems), diff --git a/src/components/navigation/navigation_entry.vue b/src/components/navigation/navigation_entry.vue index 3ab0355b1..cbebbaf47 100644 --- a/src/components/navigation/navigation_entry.vue +++ b/src/components/navigation/navigation_entry.vue @@ -47,17 +47,11 @@
- {{ getters[item.badgeGetter] }} -
-
- {{ this[`${item.store}Store`][item.badgeGetter] }} + {{ badges[item.badgeGetter] }}