diff --git a/.babelrc b/.babelrc index bc2b0e31..3c732dd1 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,5 @@ { - "presets": ["es2015", "stage-2", "env"], - "plugins": ["transform-runtime", "lodash", "transform-vue-jsx"], + "presets": ["@babel/preset-env"], + "plugins": ["@babel/plugin-transform-runtime", "lodash", "@vue/babel-plugin-transform-vue-jsx"], "comments": false } diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 35363537..0a9bbd7a 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -77,6 +77,9 @@ Use custom image for NSFW'd images ### `showFeaturesPanel` Show panel showcasing instance features/settings to logged-out visitors +### `hideSitename` +Hide instance name in header + ## Indirect configuration Some features are configured depending on how backend is configured. In general the approach is "if backend allows it there's no need to hide it, if backend doesn't allow it there's no need to show it. @@ -96,3 +99,6 @@ Setting this will change the warning text that is displayed for direct messages. ATTENTION: If you actually want the behavior to change. You will need to set the appropriate option at the backend. See the backend documentation for information about that. DO NOT activate this without checking the backend configuration first! + +### Private Mode +If the `private` instance setting is enabled in the backend, features that are not accessible without authentication, such as the timelines and search will be disabled for unauthenticated users. diff --git a/package.json b/package.json index 3c9598eb..38936b23 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,8 @@ "lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs" }, "dependencies": { + "@babel/runtime": "^7.7.6", "@chenfengyuan/vue-qrcode": "^1.0.0", - "babel-plugin-add-module-exports": "^0.2.1", - "babel-plugin-lodash": "^3.2.11", "body-scroll-lock": "^2.6.4", "chromatism": "^3.0.0", "cropperjs": "^1.4.3", @@ -40,20 +39,17 @@ "whatwg-fetch": "^2.0.3" }, "devDependencies": { - "@babel/polyfill": "^7.0.0", + "@babel/core": "^7.7.5", + "@babel/plugin-transform-runtime": "^7.7.6", + "@babel/preset-env": "^7.7.6", + "@babel/register": "^7.7.4", + "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", "@vue/test-utils": "^1.0.0-beta.26", "autoprefixer": "^6.4.0", - "babel-core": "^6.0.0", "babel-eslint": "^7.0.0", - "babel-helper-vue-jsx-merge-props": "^2.0.3", - "babel-loader": "^7.0.0", - "babel-plugin-syntax-jsx": "^6.18.0", - "babel-plugin-transform-runtime": "^6.0.0", - "babel-plugin-transform-vue-jsx": "3", - "babel-preset-env": "^1.7.0", - "babel-preset-es2015": "^6.0.0", - "babel-preset-stage-2": "^6.0.0", - "babel-register": "^6.0.0", + "babel-loader": "^8.0.6", + "babel-plugin-lodash": "^3.3.4", "chai": "^3.5.0", "chalk": "^1.1.3", "chromedriver": "^2.21.2", diff --git a/src/App.js b/src/App.js index 04a40e30..61b5eec1 100644 --- a/src/App.js +++ b/src/App.js @@ -90,6 +90,7 @@ export default { }, sitename () { return this.$store.state.instance.name }, chat () { return this.$store.state.chat.channel.state === 'joined' }, + hideSitename () { return this.$store.state.instance.hideSitename }, suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled }, showInstanceSpecificPanel () { return this.$store.state.instance.showInstanceSpecificPanel && @@ -97,7 +98,8 @@ export default { this.$store.state.instance.instanceSpecificPanelContent }, showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }, - isMobileLayout () { return this.$store.state.interface.mobileLayout } + isMobileLayout () { return this.$store.state.interface.mobileLayout }, + privateMode () { return this.$store.state.instance.private } }, methods: { scrollToTop () { diff --git a/src/App.scss b/src/App.scss index 925913f2..754ca62e 100644 --- a/src/App.scss +++ b/src/App.scss @@ -870,3 +870,16 @@ nav { transform: rotate(359deg); } } + +.new-status-notification { + position:relative; + margin-top: -1px; + font-size: 1.1em; + border-width: 1px 0 0 0; + border-style: solid; + border-color: var(--border, $fallback--border); + padding: 10px; + z-index: 1; + background-color: $fallback--fg; + background-color: var(--panel, $fallback--fg); +} diff --git a/src/App.vue b/src/App.vue index dbe842ec..1b1c2648 100644 --- a/src/App.vue +++ b/src/App.vue @@ -31,6 +31,7 @@
{ copyInstanceOption('alwaysShowSubjectInput') copyInstanceOption('noAttachmentLinks') copyInstanceOption('showFeaturesPanel') + copyInstanceOption('hideSitename') return store.dispatch('setTheme', config['theme']) } @@ -218,12 +219,21 @@ const getNodeInfo = async ({ store }) => { store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version }) store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' }) + const priv = metadata.private + store.dispatch('setInstanceOption', { name: 'private', value: priv }) + const frontendVersion = window.___pleromafe_commit_hash store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion }) store.dispatch('setInstanceOption', { name: 'tagPolicyAvailable', value: metadata.federation.mrf_policies.includes('TagPolicy') }) const federation = metadata.federation store.dispatch('setInstanceOption', { name: 'federationPolicy', value: federation }) + store.dispatch('setInstanceOption', { + name: 'federating', + value: typeof federation.enabled === 'undefined' + ? true + : federation.enabled + }) const accounts = metadata.staffAccounts await resolveStaffAccounts({ store, accounts }) diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js index 1a00a1c1..a8931787 100644 --- a/src/components/follow_request_card/follow_request_card.js +++ b/src/components/follow_request_card/follow_request_card.js @@ -7,11 +7,11 @@ const FollowRequestCard = { }, methods: { approveUser () { - this.$store.state.api.backendInteractor.approveUser(this.user.id) + this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) }, denyUser () { - this.$store.state.api.backendInteractor.denyUser(this.user.id) + this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) } } diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index 0b574a04..0d8f1da6 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -58,7 +58,7 @@ const LoginForm = { ).then((result) => { if (result.error) { if (result.error === 'mfa_required') { - this.requireMFA({ app: app, settings: result }) + this.requireMFA({ settings: result }) } else if (result.identifier === 'password_reset_required') { this.$router.push({ name: 'password-reset', params: { passwordResetRequested: true } }) } else { diff --git a/src/components/mfa_form/recovery_form.js b/src/components/mfa_form/recovery_form.js index 7a3cc22d..b25c65dd 100644 --- a/src/components/mfa_form/recovery_form.js +++ b/src/components/mfa_form/recovery_form.js @@ -8,18 +8,23 @@ export default { }), computed: { ...mapGetters({ - authApp: 'authFlow/app', authSettings: 'authFlow/settings' }), - ...mapState({ instance: 'instance' }) + ...mapState({ + instance: 'instance', + oauth: 'oauth' + }) }, methods: { ...mapMutations('authFlow', ['requireTOTP', 'abortMFA']), ...mapActions({ login: 'authFlow/login' }), clearError () { this.error = false }, submit () { + const { clientId, clientSecret } = this.oauth + const data = { - app: this.authApp, + clientId, + clientSecret, instance: this.instance.server, mfaToken: this.authSettings.mfa_token, code: this.code diff --git a/src/components/mfa_form/totp_form.js b/src/components/mfa_form/totp_form.js index 778bf8dc..b774f2d0 100644 --- a/src/components/mfa_form/totp_form.js +++ b/src/components/mfa_form/totp_form.js @@ -7,18 +7,23 @@ export default { }), computed: { ...mapGetters({ - authApp: 'authFlow/app', authSettings: 'authFlow/settings' }), - ...mapState({ instance: 'instance' }) + ...mapState({ + instance: 'instance', + oauth: 'oauth' + }) }, methods: { ...mapMutations('authFlow', ['requireRecovery', 'abortMFA']), ...mapActions({ login: 'authFlow/login' }), clearError () { this.error = false }, submit () { + const { clientId, clientSecret } = this.oauth + const data = { - app: this.authApp, + clientId, + clientSecret, instance: this.instance.server, mfaToken: this.authSettings.mfa_token, code: this.code diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js index 5a90c31f..c1166a0c 100644 --- a/src/components/mobile_nav/mobile_nav.js +++ b/src/components/mobile_nav/mobile_nav.js @@ -29,6 +29,7 @@ const MobileNav = { unseenNotificationsCount () { return this.unseenNotifications.length }, + hideSitename () { return this.$store.state.instance.hideSitename }, sitename () { return this.$store.state.instance.name } }, methods: { diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue index d1c24e56..51f1d636 100644 --- a/src/components/mobile_nav/mobile_nav.vue +++ b/src/components/mobile_nav/mobile_nav.vue @@ -17,6 +17,7 @@ { + store.state.api.backendInteractor.untagUser({ user: this.user, tag }).then(response => { if (!response.ok) { return } store.commit('untagUser', { user: this.user, tag }) }) } else { - store.state.api.backendInteractor.tagUser(this.user, tag).then(response => { + store.state.api.backendInteractor.tagUser({ user: this.user, tag }).then(response => { if (!response.ok) { return } store.commit('tagUser', { user: this.user, tag }) }) @@ -59,24 +59,19 @@ const ModerationTools = { toggleRight (right) { const store = this.$store if (this.user.rights[right]) { - store.state.api.backendInteractor.deleteRight(this.user, right).then(response => { + store.state.api.backendInteractor.deleteRight({ user: this.user, right }).then(response => { if (!response.ok) { return } - store.commit('updateRight', { user: this.user, right: right, value: false }) + store.commit('updateRight', { user: this.user, right, value: false }) }) } else { - store.state.api.backendInteractor.addRight(this.user, right).then(response => { + store.state.api.backendInteractor.addRight({ user: this.user, right }).then(response => { if (!response.ok) { return } - store.commit('updateRight', { user: this.user, right: right, value: true }) + store.commit('updateRight', { user: this.user, right, value: true }) }) } }, toggleActivationStatus () { - const store = this.$store - const status = !!this.user.deactivated - store.state.api.backendInteractor.setActivationStatus(this.user, status).then(response => { - if (!response.ok) { return } - store.commit('updateActivationStatus', { user: this.user, status: status }) - }) + this.$store.dispatch('toggleActivationStatus', { user: this.user }) }, deleteUserDialog (show) { this.showDeleteUserDialog = show @@ -85,7 +80,7 @@ const ModerationTools = { const store = this.$store const user = this.user const { id, name } = user - store.state.api.backendInteractor.deleteUser(user) + store.state.api.backendInteractor.deleteUser({ user }) .then(e => { this.$store.dispatch('markStatusesAsDeleted', status => user.id === status.user.id) const isProfile = this.$route.name === 'external-user-profile' || this.$route.name === 'user-profile' diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js index 7f783acb..d9268585 100644 --- a/src/components/nav_panel/nav_panel.js +++ b/src/components/nav_panel/nav_panel.js @@ -1,20 +1,18 @@ +import { mapState } from 'vuex' + const NavPanel = { created () { if (this.currentUser && this.currentUser.locked) { this.$store.dispatch('startFetchingFollowRequest') } }, - computed: { - currentUser () { - return this.$store.state.users.currentUser - }, - chat () { - return this.$store.state.chat.channel - }, - followRequestCount () { - return this.$store.state.api.followRequests.length - } - } + computed: mapState({ + currentUser: state => state.users.currentUser, + chat: state => state.chat.channel, + followRequestCount: state => state.api.followRequests.length, + privateMode: state => state.instance.private, + federating: state => state.instance.federating + }) } export default NavPanel diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue index 28589bb1..034259d9 100644 --- a/src/components/nav_panel/nav_panel.vue +++ b/src/components/nav_panel/nav_panel.vue @@ -4,22 +4,22 @@
  • - {{ $t("nav.timeline") }} + {{ $t("nav.timeline") }}
  • - {{ $t("nav.interactions") }} + {{ $t("nav.interactions") }}
  • - {{ $t("nav.dms") }} + {{ $t("nav.dms") }}
  • - {{ $t("nav.friend_requests") }} + {{ $t("nav.friend_requests") }}
  • -
  • +
  • - {{ $t("nav.public_tl") }} + {{ $t("nav.public_tl") }}
  • -
  • +
  • - {{ $t("nav.twkn") }} + {{ $t("nav.twkn") }}
  • - {{ $t("nav.about") }} + {{ $t("nav.about") }}
@@ -113,4 +113,8 @@ } } } + +.nav-panel .button-icon:before { + width: 1.1em; +} diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 6c4054fd..a89c0cdc 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -47,6 +47,11 @@ const Notifications = { components: { Notification }, + created () { + const { dispatch } = this.$store + + dispatch('fetchAndUpdateNotifications') + }, watch: { unseenCount (count) { if (count > 0) { diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.js b/src/components/public_and_external_timeline/public_and_external_timeline.js index f614c13b..cbd4491b 100644 --- a/src/components/public_and_external_timeline/public_and_external_timeline.js +++ b/src/components/public_and_external_timeline/public_and_external_timeline.js @@ -10,7 +10,7 @@ const PublicAndExternalTimeline = { this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' }) }, destroyed () { - this.$store.dispatch('stopFetching', 'publicAndExternal') + this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal') } } diff --git a/src/components/public_timeline/public_timeline.js b/src/components/public_timeline/public_timeline.js index 8976a99c..66c40d3a 100644 --- a/src/components/public_timeline/public_timeline.js +++ b/src/components/public_timeline/public_timeline.js @@ -10,7 +10,7 @@ const PublicTimeline = { this.$store.dispatch('startFetchingTimeline', { timeline: 'public' }) }, destroyed () { - this.$store.dispatch('stopFetching', 'public') + this.$store.dispatch('stopFetchingTimeline', 'public') } } diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue index 5bb06a4f..222b67a8 100644 --- a/src/components/registration/registration.vue +++ b/src/components/registration/registration.vue @@ -172,7 +172,7 @@ for="captcha-label" >{{ $t('captcha') }} -