mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-07-06 07:30:17 +02:00
* feat: add Sentry User Feedback widget to backoffice (#178) Install @sentry/browser via AssetMapper and initialize the feedback integration on all backoffice pages. The CDN loader script is moved to an overridable block so backoffice pages use the npm SDK without double-initialising Sentry. Sentry is initialised only when a DSN is configured (SENTRY_DSN env var). When a user is logged in their email is pre-filled in the feedback form via Sentry.setUser(); both name and email remain optional so anonymous submissions are supported by simply leaving those fields empty. * feat: add Spotlight sidecar for local Sentry development testing Add the Spotlight container to compose.override.yaml so the feedback widget and error events can be inspected locally without sending anything to Sentry. The JS SDK switches to spotlight mode automatically when no SENTRY_DSN is configured. * feat: route PHP Sentry events to Spotlight in dev Add a when@dev block to sentry.yaml that initialises the PHP Sentry SDK with a placeholder DSN and forwards all events to the Spotlight sidecar over the internal Docker network (http://spotlight:8969/stream). The JS SDK already uses localhost:8969 via spotlight:true when no real SENTRY_DSN is set, which is correct since the browser cannot reach the internal Docker hostname. * fix: use spotlight_url to route PHP dev errors to Spotlight sidecar * fix: manually mount Sentry feedback widget to work around v10 setupOnce guard Sentry v10's setupOnce() is skipped when the integration name is already in the module-level guard array, so autoInject never mounts the widget. Switching to autoInject: false and calling createWidget() directly is reliable and confirmed working in the browser. Also use the tunnel option to forward JS events to the local Spotlight sidecar when no real DSN is configured, and enable SentryBundle in dev so PHP errors are also routed to Spotlight.
This commit is contained in:
@@ -3,3 +3,35 @@ import 'bootstrap-icons/font/bootstrap-icons.min.css';
|
|||||||
import './styles/backoffice.scss';
|
import './styles/backoffice.scss';
|
||||||
import './stimulus.js';
|
import './stimulus.js';
|
||||||
import './bootstrap.js';
|
import './bootstrap.js';
|
||||||
|
import * as Sentry from '@sentry/browser';
|
||||||
|
|
||||||
|
const dsn = document.querySelector('meta[name="sentry-dsn"]')?.content ?? '';
|
||||||
|
const userEmail = document.querySelector('meta[name="user-email"]')?.content ?? '';
|
||||||
|
|
||||||
|
// When no real DSN is configured, route to the local Spotlight sidecar so
|
||||||
|
// nothing reaches Sentry. A syntactically valid DSN is still required for the
|
||||||
|
// SDK to initialise; the tunnel option redirects all transport to Spotlight.
|
||||||
|
const useSpotlight = !dsn;
|
||||||
|
const effectiveDsn = dsn || 'https://0@o0.ingest.sentry.io/0';
|
||||||
|
|
||||||
|
const feedbackIntegration = Sentry.feedbackIntegration({
|
||||||
|
colorScheme: 'system',
|
||||||
|
showName: true,
|
||||||
|
showEmail: true,
|
||||||
|
isNameRequired: false,
|
||||||
|
isEmailRequired: false,
|
||||||
|
autoInject: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: effectiveDsn,
|
||||||
|
tunnel: useSpotlight ? 'http://localhost:8969/stream' : undefined,
|
||||||
|
integrations: [feedbackIntegration],
|
||||||
|
});
|
||||||
|
|
||||||
|
// autoInject is unreliable in Sentry v10 due to the setupOnce guard; mount manually.
|
||||||
|
feedbackIntegration.createWidget();
|
||||||
|
|
||||||
|
if (userEmail) {
|
||||||
|
Sentry.setUser({ email: userEmail });
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,5 +70,10 @@ services:
|
|||||||
MP_SMTP_AUTH_ALLOW_INSECURE: 1
|
MP_SMTP_AUTH_ALLOW_INSECURE: 1
|
||||||
###< symfony/mailer ###
|
###< symfony/mailer ###
|
||||||
|
|
||||||
|
spotlight:
|
||||||
|
image: ghcr.io/getsentry/spotlight:latest
|
||||||
|
ports:
|
||||||
|
- "8969:8969"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
sass:
|
sass:
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ return [
|
|||||||
TwigExtraBundle::class => ['all' => true],
|
TwigExtraBundle::class => ['all' => true],
|
||||||
DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||||
SymfonyCastsVerifyEmailBundle::class => ['all' => true],
|
SymfonyCastsVerifyEmailBundle::class => ['all' => true],
|
||||||
SentryBundle::class => ['prod' => true],
|
SentryBundle::class => ['dev' => true, 'prod' => true],
|
||||||
SymfonycastsSassBundle::class => ['all' => true],
|
SymfonycastsSassBundle::class => ['all' => true],
|
||||||
StimulusBundle::class => ['all' => true],
|
StimulusBundle::class => ['all' => true],
|
||||||
TurboBundle::class => ['all' => true],
|
TurboBundle::class => ['all' => true],
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
when@dev:
|
||||||
|
sentry:
|
||||||
|
dsn: 'https://placeholder@placeholder.ingest.sentry.io/0'
|
||||||
|
options:
|
||||||
|
spotlight: true
|
||||||
|
spotlight_url: 'http://spotlight:8969/stream'
|
||||||
|
|
||||||
when@prod:
|
when@prod:
|
||||||
sentry:
|
sentry:
|
||||||
dsn: '%env(SENTRY_DSN)%'
|
dsn: '%env(SENTRY_DSN)%'
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
twig:
|
twig:
|
||||||
file_name_pattern: '*.twig'
|
file_name_pattern: '*.twig'
|
||||||
form_themes: [ 'bootstrap_5_layout.html.twig' ]
|
form_themes: [ 'bootstrap_5_layout.html.twig' ]
|
||||||
|
globals:
|
||||||
|
sentry_dsn: '%env(SENTRY_DSN)%'
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
twig:
|
twig:
|
||||||
|
|||||||
Generated
+3
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
// This file is auto-generated and is for apps only. Bundles SHOULD NOT rely on its content.
|
// This file is auto-generated and is for apps only. Bundles SHOULD NOT rely on its content.
|
||||||
|
|
||||||
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||||
@@ -1518,6 +1520,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* web_profiler?: WebProfilerConfig,
|
* web_profiler?: WebProfilerConfig,
|
||||||
* twig_extra?: TwigExtraConfig,
|
* twig_extra?: TwigExtraConfig,
|
||||||
* symfonycasts_verify_email?: SymfonycastsVerifyEmailConfig,
|
* symfonycasts_verify_email?: SymfonycastsVerifyEmailConfig,
|
||||||
|
* sentry?: SentryConfig,
|
||||||
* symfonycasts_sass?: SymfonycastsSassConfig,
|
* symfonycasts_sass?: SymfonycastsSassConfig,
|
||||||
* stimulus?: StimulusConfig,
|
* stimulus?: StimulusConfig,
|
||||||
* turbo?: TurboConfig,
|
* turbo?: TurboConfig,
|
||||||
|
|||||||
@@ -34,4 +34,11 @@ return [
|
|||||||
'@hotwired/stimulus' => ['version' => '3.2.2'],
|
'@hotwired/stimulus' => ['version' => '3.2.2'],
|
||||||
'@hotwired/turbo' => ['version' => '8.0.23'],
|
'@hotwired/turbo' => ['version' => '8.0.23'],
|
||||||
'bootstrap-icons/font/bootstrap-icons.min.css' => ['version' => '1.13.1', 'type' => 'css'],
|
'bootstrap-icons/font/bootstrap-icons.min.css' => ['version' => '1.13.1', 'type' => 'css'],
|
||||||
|
'@sentry/browser' => ['version' => '10.63.0'],
|
||||||
|
'@sentry/feedback' => ['version' => '10.63.0'],
|
||||||
|
'@sentry/core/browser' => ['version' => '10.63.0'],
|
||||||
|
'@sentry/browser-utils' => ['version' => '10.63.0'],
|
||||||
|
'@sentry/replay' => ['version' => '10.63.0'],
|
||||||
|
'@sentry/replay-canvas' => ['version' => '10.63.0'],
|
||||||
|
'@sentry/core' => ['version' => '10.63.0'],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
{% extends 'base.html.twig' %}
|
{% extends 'base.html.twig' %}
|
||||||
{% block importmap %}{{ importmap('backoffice') }}{% endblock %}
|
{% block importmap %}{{ importmap('backoffice') }}{% endblock %}
|
||||||
|
{% block sentry_loader %}{% endblock %}
|
||||||
|
{% block head_extra %}
|
||||||
|
<meta name="sentry-dsn" content="{{ sentry_dsn }}">
|
||||||
|
<meta name="user-email" content="{{ app.user ? app.user.userIdentifier : '' }}">
|
||||||
|
{% endblock %}
|
||||||
{% block title %}Tijd voor de test | {% endblock %}
|
{% block title %}Tijd voor de test | {% endblock %}
|
||||||
{% block nav %}{{ include('backoffice/nav.html.twig') }}{% endblock %}
|
{% block nav %}{{ include('backoffice/nav.html.twig') }}{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,17 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
{% block sentry_loader %}
|
||||||
<script
|
<script
|
||||||
src="https://js-de.sentry-cdn.com/30cf438bc708c97e6f45c127bed9af96.min.js"
|
src="https://js-de.sentry-cdn.com/30cf438bc708c97e6f45c127bed9af96.min.js"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
></script>
|
></script>
|
||||||
|
{% endblock %}
|
||||||
<title>
|
<title>
|
||||||
{% block title %}Tijd voor de test{% endblock title %}
|
{% block title %}Tijd voor de test{% endblock title %}
|
||||||
</title>
|
</title>
|
||||||
{% block importmap %}{% endblock %}
|
{% block importmap %}{% endblock %}
|
||||||
|
{% block head_extra %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block nav %}
|
{% block nav %}
|
||||||
|
|||||||
Reference in New Issue
Block a user