doc: add sentry stuff section to md docs
This commit is contained in:
@ -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>
|
||||||
|
|
||||||
|
```
|
Reference in New Issue
Block a user