doc: add sentry stuff section to md docs

This commit is contained in:
2025-07-09 15:47:02 +02:00
parent 99cd4098da
commit 8d39486d67

View File

@ -98,8 +98,10 @@ This guide details the comprehensive changes implemented to prepare the SWA Prac
- Modified the `evaluateWithGemini` function to accept the `ai` instance as a parameter, ensuring it uses the dynamically created `GoogleGenAI` instance. - Modified the `evaluateWithGemini` function to accept the `ai` instance as a parameter, ensuring it uses the dynamically created `GoogleGenAI` instance.
- Added a check within `handleSubmit` in `ExerciseSheet` to verify the `ai` instance and its `models.generateContent` method before making API calls, providing a user-friendly error message if the API key is missing or invalid. - Added a check within `handleSubmit` in `ExerciseSheet` to verify the `ai` instance and its `models.generateContent` method before making API calls, providing a user-friendly error message if the API key is missing or invalid.
- **Template Literal Escaping Fixes**: - **Template Literal Escaping Fixes**:
- Crucially, fixed syntax errors within the `systemInstruction` and `contents` template literals in `evaluateWithGemini`. The original code had issues with unescaped backticks (``` ` ```) and newlines (`\n`) when they were part of the string content itself, leading to build failures. - Crucially, fixed syntax errors within the `systemInstruction` and `contents` template literals in `evaluateWithGemini`. The original code had issues with unescaped backticks (``` ` ```) and newlines (`
- **Specific Fix**: All literal backticks within the template strings (e.g., for code blocks like ``` ```c ```) were escaped as``` \`\`\` ```. All literal newlines (`\n`) within the template strings were escaped as `\\n`. This ensures they are interpreted as literal characters within the string rather than JavaScript syntax. `) when they were part of the string content itself, leading to build failures.
- **Specific Fix**: All literal backticks within the template strings (e.g., for code blocks like ``` ```c ```) were escaped as``` \`\`\` ```. All literal newlines (`
`) within the template strings were escaped as `\\n`. This ensures they are interpreted as literal characters within the string rather than JavaScript syntax.
**Step-by-step Actions**: **Step-by-step Actions**:
@ -525,3 +527,215 @@ CMD [ "serve", "-s", "dist", "-l", "8000" ]
This enhancement makes the application more suitable for software architecture exercises that require diagram creation and visualization. This enhancement makes the application more suitable for software architecture exercises that require diagram creation and visualization.
--- ---
### 6. Optional: Implementing Sentry User Feedback
**Objective**: To provide a simple and effective way for users to provide feedback, report issues, or suggest new ideas directly from within the application.
**Previous State**: The application had no built-in feedback mechanism.
**Changes Made**:
- **Sentry SDK Update**: Replaced `@sentry/browser` with `@sentry/react` to leverage React-specific features.
- **Sentry Initialization**: Configured the Sentry SDK in `index.tsx` to include the `feedbackIntegration`, enabling the user feedback features.
- **Custom Feedback Dialog**:
- Instead of using the default Sentry feedback widget, a custom feedback dialog was implemented in `App.tsx` for a more integrated user experience.
- A "Feedback" button with a `ChatBubbleLeftRightIcon` was added to the top-right corner of the application.
- Clicking the button opens a `Dialog` (modal) from `@headlessui/react`.
- The modal contains a textarea for the user to enter their feedback, with German placeholder text.
- When the user submits the feedback, `Sentry.captureFeedback` is called to send the feedback to Sentry.
**Step-by-step Actions**:
1. Remove `@sentry/browser` and add `@sentry/react` to `package.json`.
2. Update `index.tsx` to import from `@sentry/react` and add the `feedbackIntegration` to the `Sentry.init` call.
3. In `App.tsx`, import `ChatBubbleLeftRightIcon` from `@heroicons/react/24/outline` and `* as Sentry from "@sentry/react"`.
4. Add state variables for the feedback dialog visibility and the feedback message.
5. Add a "Feedback" button next to the "Settings" button.
6. Implement the custom feedback `Dialog` component with a textarea and submit/cancel buttons.
7. Create a handler function that calls `Sentry.captureFeedback` with the user's message.
8. Write the modified content back to the respective files.
**Code Changes (package.json)**:
```diff
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
"dependencies": {
"@google/genai": "latest",
"@headlessui/react": "^2.2.4",
- "@heroicons/react": "^2.2.0",
- "@sentry/browser": "^9.36.0",
+ "@heroicons/react": "^2.2.0",
+ "@sentry/react": "9.36.0",
"diff": "5.2.0",
"mermaid": "^11.8.1",
"prismjs": "1.29.0",
```
**Code Changes (index.tsx)**:
```diff
--- a/index.tsx
+++ b/index.tsx
@@ -1,8 +1,15 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
-import * as Sentry from "@sentry/browser";
+import * as Sentry from "@sentry/react";
-Sentry.init({ dsn: "https://2851a11b9f1b4715b389979628da322f@glitchtip.yandrik.dev/3" });
+Sentry.init({
+ dsn: "https://2851a11b9f1b4715b389979628da322f@glitchtip.yandrik.dev/3",
+ integrations: [
+ Sentry.feedbackIntegration({
+ colorScheme: "system",
+ }),
+ ],
+});
const rootElement = document.getElementById('root');
if (!rootElement) {
```
**Code Changes (App.tsx)**:
```diff
--- a/App.tsx
+++ b/App.tsx
@@ -1,7 +1,8 @@
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { Dialog } from "@headlessui/react";
-import { Cog6ToothIcon } from "@heroicons/react/24/outline";
+import { Cog6ToothIcon, ChatBubbleLeftRightIcon } from "@heroicons/react/24/outline";
import { Exercise, CheckResult, ExercisePartType } from './types';
+import * as Sentry from "@sentry/react";
import { swaExercises1 } from './data/swa_exercises.1';
import { swaExercises2 } from './data/swa_exercises.2';
import { swaExercises3 } from './data/swa_exercises.3';
@@ -564,6 +565,18 @@
const [exercises, setExercises] = useState<Exercise[]>([]);
const [currentIndex, setCurrentIndex] = useState(0);
+ const [showFeedback, setShowFeedback] = useState(false);
+ const [feedbackMessage, setFeedbackMessage] = useState('');
+
+ const handleFeedbackSubmit = () => {
+ Sentry.captureFeedback({
+ message: feedbackMessage,
+ });
+ setFeedbackMessage('');
+ setShowFeedback(false);
+ };
+
+
// --- API KEY STATE ---
const [apiKey, setApiKey] = useState<string>('');
const [showSettings, setShowSettings] = useState(false);
@@ -604,12 +617,60 @@
return (
<div className="min-h-screen flex flex-col p-4 md:p-8">
+ {/* Feedback Button */}
+ <button
+ className="fixed top-4 right-16 z-50 bg-white rounded-full p-2 shadow hover:bg-slate-100 transition"
+ aria-label="Feedback"
+ onClick={() => setShowFeedback(true)}
+ >
+ <ChatBubbleLeftRightIcon className="w-7 h-7 text-slate-600" />
+ </button>
{/* Settings Button */}
<button
className="fixed top-4 right-4 z-50 bg-white rounded-full p-2 shadow hover:bg-slate-100 transition"
aria-label="API Key Settings"
onClick={() => setShowSettings(true)}
>
<Cog6ToothIcon className="w-7 h-7 text-slate-600" />
</button>
{/* Settings Modal */}
<Dialog open={showSettings} onClose={() => setShowSettings(false)} className="relative z-50">
+ <div className="fixed inset-0 bg-black/30" aria-hidden="true" />
+ <div className="fixed inset-0 flex items-center justify-center p-4">
+ <Dialog.Panel className="bg-white rounded-lg shadow-xl p-8 max-w-md w-full">
+ <Dialog.Title className="font-bold text-lg mb-4 flex items-center gap-2">
+ <Cog6ToothIcon className="w-6 h-6 text-blue-600" />
+ Gemini API Key
+ </Dialog.Title>
+ <div className="mb-4">
+ <input
+ type="text"
+ className="w-full border rounded px-3 py-2 text-slate-800"
+ value={inputKey}
+ onChange={e => setInputKey(e.target.value)}
+ placeholder="Enter Gemini API Key"
+ />
+ </div>
+ <div className="flex justify-end gap-2">
+ <button
+ className="px-4 py-2 rounded bg-slate-200 text-slate-700 hover:bg-slate-300"
+ onClick={() => setShowSettings(false)}
+ >
+ Cancel
+ </button>
+ <button
+ className="px-4 py-2 rounded bg-blue-600 text-white font-bold hover:bg-blue-700"
+ onClick={handleSaveKey}
+ disabled={!inputKey.trim()}
+ >
+ Save
+ </button>
+ </div>
+ <div className="mt-4 text-xs text-slate-500">
+ Your API key is stored in your browser only.
+ </div>
+ <div className="mt-2 text-xs text-slate-500">
+ Get an API key at <a href="https://aistudio.google.com/" target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline">https://aistudio.google.com/</a> - this app uses gemini-2.5-flash, which is free for 500 requests a day (as of 9.7.2025)
+ </div>
+ </Dialog.Panel>
+ </div>
+ </Dialog>
+ {/* Feedback Modal */}
+ <Dialog open={showFeedback} onClose={() => setShowFeedback(false)} className="relative z-50">
+ <div className="fixed inset-0 bg-black/30" aria-hidden="true" />
+ <div className="fixed inset-0 flex items-center justify-center p-4">
+ <Dialog.Panel className="bg-white rounded-lg shadow-xl p-8 max-w-md w-full">
+ <Dialog.Title className="font-bold text-lg mb-4 flex items-center gap-2">
+ <ChatBubbleLeftRightIcon className="w-6 h-6 text-blue-600" />
+ Feedback, Aufgabenideen, oder was auch immer
+ </Dialog.Title>
+ <div className="mb-4">
+ <textarea
+ className="w-full border rounded px-3 py-2 text-slate-800"
+ value={feedbackMessage}
+ onChange={e => setFeedbackMessage(e.target.value)}
+ placeholder="Was kann ich besser machen?"
+ rows={5}
+ />
+ </div>
+ <div className="flex justify-end gap-2">
+ <button
+ className="px-4 py-2 rounded bg-slate-200 text-slate-700 hover:bg-slate-300"
+ onClick={() => setShowFeedback(false)}
+ >
+ Abbrechen
+ </button>
+ <button
+ className="px-4 py-2 rounded bg-blue-600 text-white font-bold hover:bg-blue-700"
+ onClick={handleFeedbackSubmit}
+ disabled={!feedbackMessage.trim()}
+ >
+ Senden
+ </button>
+ </div>
+ </Dialog.Panel>
+ </div>
+ </Dialog>
<header className="mb-6 flex-shrink-0">
<h1 className="text-3xl font-serif font-bold text-slate-800">SWA Trainer</h1>
<p className="text-slate-500">Interaktive Übungen zur Vorbereitung auf die SWA-Klausur</p>
```