diff --git a/front/package.json b/front/package.json index e44039523..88ce4b247 100644 --- a/front/package.json +++ b/front/package.json @@ -45,6 +45,7 @@ "text-clipper": "2.2.0", "tiptap-markdown": "^0.5.0", "transliteration": "2.3.5", + "universal-cookie": "^4.0.4", "vue": "3.2.37", "vue-gettext": "2.1.12", "vue-plyr": "7.0.0", diff --git a/front/src/components/common/RenderedDescription.vue b/front/src/components/common/RenderedDescription.vue index 35f9529f6..32cb39d81 100644 --- a/front/src/components/common/RenderedDescription.vue +++ b/front/src/components/common/RenderedDescription.vue @@ -8,7 +8,6 @@ import axios from 'axios' import clip from 'text-clipper' interface Emits { - // TODO (wvffle): Find correct type (e: 'updated', data: unknown): void } diff --git a/front/src/init/sentry.ts b/front/src/init/sentry.ts index a031279b6..7c1c68dd8 100644 --- a/front/src/init/sentry.ts +++ b/front/src/init/sentry.ts @@ -1,34 +1,77 @@ import type { InitModule } from '~/types' +import type { Router } from 'vue-router' +import type { App } from 'vue' import * as Sentry from '@sentry/vue' import { BrowserTracing } from '@sentry/tracing' +import { useCookies } from '@vueuse/integrations/useCookies' +import { gettext } from '~/init/locale' -export const install: InitModule = ({ app, router }) => { +const COOKIE = 'allow-tracing' + +const initSentry = (app: App, router: Router) => { + Sentry.init({ + app, + dsn: import.meta.env.VUE_SENTRY_DSN, + logErrors: true, + trackComponents: true, + integrations: [ + new BrowserTracing({ + routingInstrumentation: Sentry.vueRouterInstrumentation(router) + }) + ], + // Set tracesSampleRate to 1.0 to capture 100% + // of transactions for performance monitoring. + // We recommend adjusting this value in production + tracesSampleRate: 1.0 + }) +} + +export const install: InitModule = ({ app, router, store }) => { if (import.meta.env.VUE_SENTRY_DSN) { - if (import.meta.env.DEV) { - if (!document.cookie.split(';').map(cookie => cookie.split('=')[0].trim()).includes('sentry_dev')) { - alert(`This instance uses ${new URL(import.meta.env.VUE_SENTRY_DSN).hostname} to collect information about crashes and stack traces.\n\nPlease unlock the domain in your adblock to allow us debug the branch.\n\nIf you do not want to share the data with us, please delete \`x-test-server\` cookie.`) + const { get, set } = useCookies() - const expires = new Date() - expires.setTime(expires.getTime() + (100 * 24 * 60 * 60 * 1000)) - document.cookie = `sentry_dev=1;expires=${expires.toUTCString()}` - } + const allowed = get(COOKIE) + + if (allowed === 'yes') { + return initSentry(app, router) } - Sentry.init({ - app, - dsn: import.meta.env.VUE_SENTRY_DSN, - logErrors: true, - trackComponents: true, - integrations: [ - new BrowserTracing({ - routingInstrumentation: Sentry.vueRouterInstrumentation(router) - }) - ], - // Set tracesSampleRate to 1.0 to capture 100% - // of transactions for performance monitoring. - // We recommend adjusting this value in production - tracesSampleRate: 1.0 - }) + if (allowed === undefined) { + const { $pgettext } = gettext + const { hostname, origin } = new URL(import.meta.env.VUE_SENTRY_DSN) + return store.commit('ui/addMessage', { + content: hostname === 'am.funkwhale.audio' + ? $pgettext( + 'App/Message/Paragraph', + 'To enhance the quality of our services, we would like to collect information about crashes during your session.
The stack traces will be shared to Funkwhale\'s official Glitchtip instance in order to help us understand how and when the errors occur.', + { hostname, origin } + ) + : $pgettext( + 'App/Message/Paragraph', + 'To enhance the quality of our services, we would like to collect information about crashes during your session.
The stack traces will be shared to %{hostname} in order to help us understand how and when the errors occur.', + { hostname, origin } + ), + date: new Date(), + key: 'allowSentryTracing', + displayTime: 0, + classActions: 'bottom attached opaque', + actions: [ + { + text: $pgettext('App/Message/Paragraph', 'Allow'), + class: 'primary', + click: () => { + set(COOKIE, 'yes') + initSentry(app, router) + } + }, + { + text: $pgettext('App/Message/Paragraph', 'Deny'), + class: 'basic', + click: () => set(COOKIE, 'no') + } + ] + }) + } } } diff --git a/front/src/style/globals/_layout.scss b/front/src/style/globals/_layout.scss index 8189b0b77..a6759410f 100644 --- a/front/src/style/globals/_layout.scss +++ b/front/src/style/globals/_layout.scss @@ -44,7 +44,7 @@ flex-direction: column; &.has-bottom-player { padding-bottom: $bottom-player-height; - .toast-container { + + .toast-container { bottom: $bottom-player-height + 1rem; pointer-events: none; } @@ -53,6 +53,8 @@ .toast-container { pointer-events: none; + top: 1em; + min-height: auto !important; > div { pointer-events: auto; diff --git a/front/yarn.lock b/front/yarn.lock index 2abc96728..4737e50a6 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -1631,6 +1631,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/cookie@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" + integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== + "@types/dompurify@2.3.3": version "2.3.3" resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.3.tgz#c24c92f698f77ed9cc9d9fa7888f90cf2bfaa23f" @@ -3213,6 +3218,11 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" +cookie@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + core-js-compat@^3.21.0, core-js-compat@^3.22.1: version "3.25.0" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.0.tgz#489affbfbf9cb3fa56192fe2dd9ebaee985a66c5" @@ -7246,6 +7256,14 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" +universal-cookie@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-4.0.4.tgz#06e8b3625bf9af049569ef97109b4bb226ad798d" + integrity sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw== + dependencies: + "@types/cookie" "^0.3.3" + cookie "^0.4.0" + universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"