feat: add i18n support and implement Grafana plugin

Adds internationalization support in filters and origins pages by 
importing the useI18n function. Expands ESLint configuration to 
include new rules and plugins, ensuring improved code quality. 
Introduces Grafana monitoring plugin to enhance performance 
tracking capabilities in the application.
This commit is contained in:
2025-06-13 15:21:27 +02:00
parent 7bbd8f522a
commit c80fd0313c
28 changed files with 1989 additions and 1948 deletions
+46
View File
@@ -0,0 +1,46 @@
import { FetchTransport, getWebInstrumentations, initializeFaro,InternalLoggerLevel } from '@grafana/faro-web-sdk'
import { TracingInstrumentation } from '@grafana/faro-web-tracing'
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'
import { envConfig } from '~/utils/environment'
const config = envConfig(window.location.hostname)
export default defineNuxtPlugin((nuxtApp) => {
if (config.grafanaUrl) {
const faro = initializeFaro({
app: {
name: 'Shiny Frontend',
version: '1.0.0',
environment: config.name,
},
sessionTracking: {
samplingRate: config.tracesSampleRate,
},
instrumentations: [
// Mandatory, omits default instrumentations otherwise.
...getWebInstrumentations(),
// Tracing package to get end-to-end visibility for HTTP requests.
new TracingInstrumentation({
instrumentations: [
new FetchInstrumentation({
ignoreUrls: [
config.grafanaUrl,
config.apiUrl,
new RegExp('.*/sw.js$'),
new RegExp('.*_payload.json.*'),
new RegExp(`https://${config.auth.domain}/*`),
],
}),
],
}),
],
internalLoggerLevel: InternalLoggerLevel.VERBOSE,
transports: [
new FetchTransport({ url: config.grafanaUrl }),
],
})
console.log(`initialized faro for ${config.grafanaUrl}, sample-rate ${config.tracesSampleRate * 100}%`)
nuxtApp.provide('faro', faro)
}
})
+26 -18
View File
@@ -1,18 +1,12 @@
import {
ApolloClient,
createHttpLink,
from,
InMemoryCache,
split,
} from '@apollo/client/core'
import { WebSocketLink } from '@apollo/client/link/ws'
import { ApolloClient, ApolloLink, createHttpLink, from, InMemoryCache, split } from '@apollo/client/core'
import { setContext } from '@apollo/client/link/context'
import { WebSocketLink } from '@apollo/client/link/ws'
import { getMainDefinition } from '@apollo/client/utilities'
import { SentryLink } from 'apollo-link-sentry'
import * as Sentry from '@sentry/browser'
import type { GetTokenSilentlyOptions } from '@auth0/auth0-spa-js'
import { DefaultApolloClient, provideApolloClient } from '@vue/apollo-composable'
import type { Auth0VueClient } from '@auth0/auth0-vue'
import { SpanKind, TraceFlags } from '@opentelemetry/api'
import { DefaultApolloClient, provideApolloClient } from '@vue/apollo-composable'
import { defineNuxtPlugin, useNuxtApp } from '#app'
import { envConfig } from '~/utils/environment'
@@ -27,12 +21,7 @@ const cache = new InMemoryCache({
const getToken = async (options: GetTokenSilentlyOptions) => {
const nuxtApp = useNuxtApp()
const auth0: Auth0VueClient = nuxtApp.$auth0 as Auth0VueClient
return await auth0.getAccessTokenSilently(options).catch((err) => {
Sentry.captureException(err, {
extra: {
function: 'getTokenSilently',
},
})
return await auth0.getAccessTokenSilently(options).catch(() => {
return undefined
})
}
@@ -63,9 +52,28 @@ const authLink = setContext(async (_, { headers }) => {
}))
})
const createSpanLink = new ApolloLink((operation, forward) => {
const nuxtApp = useNuxtApp()
if (nuxtApp.$faro) {
const { trace } = nuxtApp.$faro.api.getOTEL()
const span = trace.getTracer('default').startSpan(`gql.${operation.operationName}`, {
kind: SpanKind.INTERNAL, // 0: Internal, 1: Server, 2: Client, 3: Producer, 4: Consumer
})
const spanContext = span.spanContext()
const traceParent = '00' + '-' + spanContext.traceId + '-' + spanContext.spanId + '-0' + Number(spanContext.traceFlags || TraceFlags.NONE).toString(16)
operation.setContext({ span, headers: { ...operation.getContext().headers, 'traceparent': traceParent } })
return forward(operation).map((data) => {
span.end()
return data
})
}
return forward(operation)
})
const link =
from([
new SentryLink({}),
createSpanLink,
split(
({ query }) => {
const definition = getMainDefinition(query)
+1
View File
@@ -1,4 +1,5 @@
import { createAuth0 } from '@auth0/auth0-vue'
import { defineNuxtPlugin } from '#app'
import { envConfig } from '~/utils/environment'
-5
View File
@@ -1,5 +0,0 @@
import { createSentryPiniaPlugin } from '@sentry/vue'
export default defineNuxtPlugin(({ $pinia }) => {
$pinia.use(createSentryPiniaPlugin())
})
+4 -3
View File
@@ -1,9 +1,10 @@
import { createVuetify } from 'vuetify'
import { defineNuxtPlugin } from '#app'
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import { defineNuxtPlugin } from '#app'
export default defineNuxtPlugin((app) => {
const vuetify = createVuetify({
theme: {