Просмотр исходного кода

fix(bug-report): stopping debug logging no longer sends the report (issue #3363)

- "Stop & Submit" turned debug logging off and filed a public GitHub
  issue in the same click, and the 5-minute auto-stop did the same
  with nobody watching. The reporter only wanted a log and clicked it
  a second after starting.
- The button is now "Stop Logging". Stopping collects the logs and
  ends on a review that says a public issue will be created (with the
  description, screenshot, email, system info and logs) and how many
  log lines were collected, with Submit and Discard.
- Closing the panel keeps the review. A failed send goes back to it
  with the logs kept, also after closing and reopening the panel.
- README and a Layout comment no longer describe the old flow.
maziggy 1 день назад
Родитель
Сommit
fef8d2ec6f

+ 1 - 0
CHANGELOG.md

@@ -175,6 +175,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **The frontend build no longer warns about `path` and `crypto` being externalized for the STEP previewer (#2976)** — `occt-import-js`, the Emscripten build behind STEP previews, requires both modules, but only inside its `ENVIRONMENT_IS_NODE` branches; in the browser it loads its `.wasm` from the URL the preview worker passes and draws randomness from `crypto.getRandomValues`. Vite still externalized both and printed two warnings on every build. `vite.config.ts` now drops exactly those two warnings for that one package through `build.rolldownOptions.onLog`, so an externalization anywhere else, or of any other module, still shows.
 
 ### Fixed
+- **A bug report is no longer sent when debug logging stops (#3363, reported by @choumarin)** — "Stop & Submit" turned debug logging off and filed the report as a public GitHub issue in the same click, and the 5-minute auto-stop did the same with nobody watching, so a report meant only to capture a log was sent before it was ready. The button is now "Stop Logging": it collects the logs and ends on a review that says a public issue will be created and how many log lines were collected, with Submit and Discard. Closing the panel keeps the review, and a failed send goes back to it with the logs kept.
 - **A camera turned sideways fits the camera window (#3362, reported by @BurgerKerman)** — With a camera's rotation set to 90 or 270 degrees, the camera window that floats over the page laid the picture out as if it were still landscape and then turned it, so it was cut off in a wide window and surrounded by black bars in a tall one. It now fits whatever size the window is resized to, as the camera page opened in its own browser window already did. The same happened to Cam Wall tiles, where a portrait camera was cut off at the top and bottom, and to the classic stream overlay without a fixed layout; both are fixed too. The camera page in its own window sized the picture to the screen rather than the space below its header, which cut a little off the top and bottom in a wide window; it fits the space now.
 - **A SpoolBuddy kiosk no longer gets stuck on the login page during a database problem (#3360, reported by @sargonas)** — A kiosk signs in with its API key from the launch URL. When it loaded while Bambuddy's database was unavailable (out of connections, or a read-only replica after a failover), it gave up after three quick tries and showed the login page, which a touch-only screen can't use, until the next reboot. Pages now wait on a "Can't reach Bambuddy. Retrying…" screen and keep trying in the background, then show the page as soon as Bambuddy answers. A key or session Bambuddy reports as invalid, expired or belonging to a deactivated account still goes to the login page. This also covers browser tabs with a saved sign-in, which used to show the login page, or the app as if sign-in were off, when they loaded during an outage. Writing an API key's last-used time no longer refuses a key that has already been checked: if the write fails, the key is accepted and the failure logged. That time is now written at most once a minute instead of on every request, which takes one write and commit off almost every request made with a key. A write that fails is not tried again for a minute either. Camera tokens for the Cam Wall, stream overlays and camera streams get the same treatment: a failed last-used write no longer refuses a valid token.
 - **Slicing for the Cool Plate SuperTack works (#3359, reported by @Akaviiii)** — Picking **Cool Plate SuperTack** in the Slice dialog sent a plate name neither Bambu Studio nor OrcaSlicer knows. The slicer then sliced for the Cool Plate and failed with "Filaments are not compatible with the plate type". **Smooth PEI Plate** had the same problem: the slicers call that plate High Temp Plate, so the dialog now offers it once, as **Smooth PEI Plate / High Temp Plate**. Slicer pipelines saved with either option slice on the right plate without being saved again. A plate name no slicer knows is now refused when slicing through the API or saving a pipeline, instead of being sliced as Cool Plate, and so is OrcaSlicer's Textured Cool Plate when Bambu Studio does the slicing. A pipeline holding a plate the dialog doesn't list shows that plate when it is applied, instead of showing Auto, and a run of a pipeline with a plate no slicer knows fails with a message saying so. Files sliced for OrcaSlicer's Textured Cool Plate now also record their bed temperature.

+ 1 - 1
README.md

@@ -409,7 +409,7 @@ Optional but recommended — drop the [`slicer-api/` Compose stack](slicer-api/R
 - Debug logging toggle with live indicator
 - Live application log viewer with filtering
 - Support bundle generator with comprehensive diagnostics (privacy-filtered)
-- **In-app bug reporting** — Submit bug reports directly from the UI with optional screenshot (upload, paste, or drag & drop), interactive debug log capture (start logging, reproduce at your own pace, stop & submit), and system info. Reports create GitHub issues via a secure relay. Privacy-first: all logs are sanitized and sensitive data (IPs, serials, credentials) is never included.
+- **In-app bug reporting** — Submit bug reports directly from the UI with optional screenshot (upload, paste, or drag & drop), interactive debug log capture (start logging, reproduce at your own pace, stop, then review and submit or discard), and system info. Reports create GitHub issues via a secure relay. Privacy-first: all logs are sanitized and sensitive data (IPs, serials, credentials) is never included.
 
 ### 🔒 Optional Authentication
 - Enable/disable authentication any time

+ 152 - 14
frontend/src/__tests__/components/BugReportBubble.test.tsx

@@ -173,11 +173,8 @@ describe('BugReportBubble', () => {
       expect(screen.queryByTestId('bug-report-step-reproduce')).toBeInTheDocument();
     });
 
-    // Find and click the Stop & Submit button
-    const stopBtn = screen.getAllByRole('button').find(
-      (b) => b.className.includes('bg-red-500') && !b.className.includes('rounded-full')
-    );
-    if (stopBtn) await user.click(stopBtn);
+    await user.click(screen.getByRole('button', { name: 'Stop Logging' }));
+    await user.click(await screen.findByRole('button', { name: 'Submit' }));
 
     await waitFor(
       () => {
@@ -215,10 +212,8 @@ describe('BugReportBubble', () => {
       expect(screen.queryByTestId('bug-report-step-reproduce')).toBeInTheDocument();
     });
 
-    const stopBtn = screen.getAllByRole('button').find(
-      (b) => b.className.includes('bg-red-500') && !b.className.includes('rounded-full')
-    );
-    if (stopBtn) await user.click(stopBtn);
+    await user.click(screen.getByRole('button', { name: 'Stop Logging' }));
+    await user.click(await screen.findByRole('button', { name: 'Submit' }));
 
     await waitFor(
       () => {
@@ -372,7 +367,7 @@ describe('BugReportBubble', () => {
       await closePanel(user);
 
       // Closing is not cancelling: the log level only comes back down when the
-      // user presses Stop & Submit.
+      // user presses Stop Logging.
       expect(stopCalls).toBe(0);
 
       // The disc carries the run's colour, so a closed panel still says a
@@ -383,10 +378,8 @@ describe('BugReportBubble', () => {
       await user.click(disc);
       expect(screen.getByTestId('bug-report-step-reproduce')).toBeInTheDocument();
 
-      const stopBtn = screen.getAllByRole('button').find(
-        (b) => b.className.includes('bg-red-500') && !b.className.includes('rounded-full')
-      );
-      if (stopBtn) await user.click(stopBtn);
+      await user.click(screen.getByRole('button', { name: 'Stop Logging' }));
+      await user.click(await screen.findByRole('button', { name: 'Submit' }));
 
       await waitFor(() => expect(submitted).not.toBeNull());
       expect(submitted!.description).toBe('Queue page freezes');
@@ -467,4 +460,149 @@ describe('BugReportBubble', () => {
       expect(screen.getByRole('button').className).toContain('bg-red-500');
     });
   });
+
+  describe('stopping holds the report for review (#3363)', () => {
+    afterEach(() => {
+      vi.mocked(localStorage.getItem).mockReset();
+    });
+
+    /** Counts the calls and records what was submitted. */
+    const setupRun = (submitResult: Record<string, unknown> = { success: true, message: 'ok', issue_number: 9 }) => {
+      const calls = { stop: 0, submit: 0, submitted: null as { debug_logs?: string } | null };
+      server.use(
+        http.post('*/bug-report/start-logging', () => HttpResponse.json({ started: true, was_debug: false })),
+        http.post('*/bug-report/stop-logging', () => {
+          calls.stop += 1;
+          return HttpResponse.json({ logs: 'line one\nline two\nline three\n' });
+        }),
+        http.post('*/bug-report/submit', async ({ request }) => {
+          calls.submit += 1;
+          calls.submitted = (await request.json()) as { debug_logs?: string };
+          return HttpResponse.json(submitResult);
+        }),
+      );
+      return calls;
+    };
+
+    const startAndStop = async (user: ReturnType<typeof userEvent.setup>) => {
+      await user.click(screen.getByRole('button'));
+      await user.type(getDescriptionTextarea(), 'Archive links do nothing');
+      await user.click(screen.getByRole('button', { name: 'Start Debug Logging' }));
+      await user.click(await screen.findByRole('button', { name: 'Stop Logging' }));
+      await screen.findByTestId('bug-report-review');
+    };
+
+    it('stops logging without filing anything and says what would be sent', async () => {
+      const user = userEvent.setup();
+      const calls = setupRun();
+      render(<BugReportBubble />);
+
+      await startAndStop(user);
+
+      expect(calls.stop).toBe(1);
+      expect(calls.submit).toBe(0);
+      expect(screen.getByText(/public issue on GitHub/)).toBeInTheDocument();
+      expect(screen.getByText('Log lines collected: 3')).toBeInTheDocument();
+    });
+
+    it('submits the held logs from the review', async () => {
+      const user = userEvent.setup();
+      const calls = setupRun();
+      render(<BugReportBubble />);
+
+      await startAndStop(user);
+      await user.click(screen.getByRole('button', { name: 'Submit' }));
+
+      await screen.findByText('Your bug report has been submitted.');
+      expect(calls.submit).toBe(1);
+      expect(calls.submitted!.debug_logs).toBe('line one\nline two\nline three\n');
+      expect(calls.stop).toBe(1);
+    });
+
+    it('discarding sends nothing and starts over', async () => {
+      const user = userEvent.setup();
+      const calls = setupRun();
+      render(<BugReportBubble />);
+
+      await startAndStop(user);
+      await user.click(screen.getByRole('button', { name: 'Discard' }));
+
+      await waitFor(() => expect(screen.queryByTestId('bug-report-review')).not.toBeInTheDocument());
+      await user.click(screen.getByRole('button'));
+      expect(getDescriptionTextarea().value).toBe('');
+      expect(calls.submit).toBe(0);
+    });
+
+    it('keeps the review through a close', async () => {
+      const user = userEvent.setup();
+      const calls = setupRun();
+      render(<BugReportBubble />);
+
+      await startAndStop(user);
+      const closeButton = screen.getAllByRole('button').find((b) => b.querySelector('.lucide-x'));
+      await user.click(closeButton!);
+      await waitFor(() => expect(screen.queryByTestId('bug-report-review')).not.toBeInTheDocument());
+
+      await user.click(screen.getByRole('button'));
+      expect(screen.getByTestId('bug-report-review')).toBeInTheDocument();
+      await user.click(screen.getByRole('button', { name: 'Submit' }));
+      await waitFor(() => expect(calls.submit).toBe(1));
+      expect(calls.submitted!.debug_logs).toBe('line one\nline two\nline three\n');
+    });
+
+    it('a failed send goes back to the review, logs kept', async () => {
+      const user = userEvent.setup();
+      const calls = setupRun({ success: false, message: 'Relay not available' });
+      render(<BugReportBubble />);
+
+      await startAndStop(user);
+      await user.click(screen.getByRole('button', { name: 'Submit' }));
+      await screen.findByText(/Relay not available/);
+      await user.click(screen.getByRole('button', { name: 'Submit' }));
+
+      expect(await screen.findByTestId('bug-report-review')).toBeInTheDocument();
+      expect(calls.submit).toBe(1);
+      expect(calls.stop).toBe(1);
+    });
+
+    it('a failed send closed and reopened comes back on the review, logs kept', async () => {
+      const user = userEvent.setup();
+      const calls = setupRun({ success: false, message: 'Relay not available' });
+      render(<BugReportBubble />);
+
+      await startAndStop(user);
+      await user.click(screen.getByRole('button', { name: 'Submit' }));
+      await screen.findByText(/Relay not available/);
+      await user.click(screen.getByRole('button', { name: 'Close' }));
+      await waitFor(() => expect(screen.queryByText(/Relay not available/)).not.toBeInTheDocument());
+
+      await user.click(screen.getByRole('button'));
+      expect(screen.getByTestId('bug-report-review')).toBeInTheDocument();
+      await user.click(screen.getByRole('button', { name: 'Submit' }));
+      await waitFor(() => expect(calls.submit).toBe(2));
+      expect(calls.submitted!.debug_logs).toBe('line one\nline two\nline three\n');
+    });
+
+    it('the 5-minute cap stops logging and waits for the user', async () => {
+      const calls = setupRun();
+      const startedAt = Date.now() - 299_000;
+      vi.mocked(localStorage.getItem).mockImplementation((key: string) =>
+        key === 'bambuddy-bug-report-session'
+          ? JSON.stringify({ description: 'left running', email: '', wasDebug: false, startedAt })
+          : null
+      );
+      server.use(
+        http.get('*/support/debug-logging', () =>
+          HttpResponse.json({ enabled: true, enabled_at: new Date(startedAt).toISOString(), duration_seconds: 299 })
+        ),
+      );
+
+      render(<BugReportBubble />);
+
+      // The cap opens the panel on the review rather than filing behind the user.
+      expect(await screen.findByTestId('bug-report-review', {}, { timeout: 5000 })).toBeInTheDocument();
+      expect(calls.stop).toBe(1);
+      expect(calls.submit).toBe(0);
+    });
+  });
 });

+ 63 - 12
frontend/src/components/BugReportBubble.tsx

@@ -8,7 +8,7 @@ import { SystemHealthPanel } from './SystemHealthPanel';
 import { Collapsible } from './Collapsible';
 import { useIsMobile } from '../hooks/useIsMobile';
 
-type ViewState = 'form' | 'logging' | 'stopping' | 'submitting' | 'success' | 'error';
+type ViewState = 'form' | 'logging' | 'stopping' | 'review' | 'submitting' | 'success' | 'error';
 
 /** One scanned printer paired with its name — the diagnostic result alone
  *  carries no name, and the bug-report panel lists affected printers by name. */
@@ -159,6 +159,11 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
   const [elapsedSeconds, setElapsedSeconds] = useState(0);
   const [startedAt, setStartedAt] = useState<number | null>(null);
   const [wasDebug, setWasDebug] = useState(false);
+  // Logs from a stopped run, held until the user submits or discards them
+  // (#3363). Stopping never files the report by itself.
+  const [heldLogs, setHeldLogs] = useState<string | null>(null);
+  const heldLogsRef = useRef(heldLogs);
+  heldLogsRef.current = heldLogs;
   const modalRef = useRef<HTMLDivElement>(null);
   const fileInputRef = useRef<HTMLInputElement>(null);
   const handleStopLoggingRef = useRef<() => void>(() => {});
@@ -229,11 +234,18 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
   // A run in progress is the exception (#2847). Step 2 asks the user to
   // reproduce the problem, which usually means reaching a part of the app the
   // panel is sitting on top of, so closing it has to be allowed — and the only
-  // thing that stops debug logging is the Stop & Submit button on the step this
-  // reset used to throw away.
+  // thing that stops debug logging is the Stop Logging button on the step this
+  // reset used to throw away. A stopped run's logs are kept the same way: on
+  // the review, while sending, and after a failed send, which reopens on the
+  // review (#3363). Debug logging is already off by then, so they cannot be
+  // captured again.
   useEffect(() => {
     if (!isOpen) return;
-    if (viewStateRef.current === 'logging' || viewStateRef.current === 'stopping' || viewStateRef.current === 'submitting') return;
+    if (['logging', 'stopping', 'review', 'submitting'].includes(viewStateRef.current)) return;
+    if (viewStateRef.current === 'error' && heldLogsRef.current !== null) {
+      setViewState('review');
+      return;
+    }
     setViewState('form');
     setDescription('');
     setEmail('');
@@ -244,6 +256,7 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
     setElapsedSeconds(0);
     setStartedAt(null);
     setWasDebug(false);
+    setHeldLogs(null);
   }, [isOpen]);
 
   // Pick a run back up after a reload. The panel's own state is gone by then,
@@ -366,8 +379,8 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
   };
 
   const handleStopLogging = async () => {
-    // The cap can fire while the panel is closed, and stopping submits. Show
-    // the panel so that happens in front of the user instead of behind them.
+    // The cap can fire while the panel is closed. Show the panel so the review
+    // it ends on is in front of the user instead of behind them.
     setIsOpen(true);
     // The run is over from here whichever way it goes, so there is nothing left
     // to resume — including when stopping fails, where the banner in Layout is
@@ -377,7 +390,10 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
     setViewState('stopping');
     try {
       const stopResult = await bugReportApi.stopLogging(wasDebug);
-      await handleSubmitReport(stopResult.logs);
+      // A public GitHub issue is filed only from the review step: a click on
+      // stop (#3363) or the 5-minute cap is not a decision to send.
+      setHeldLogs(stopResult.logs ?? '');
+      setViewState('review');
     } catch (err) {
       setErrorMessage(err instanceof Error ? err.message : t('bugReport.unexpectedError'));
       setViewState('error');
@@ -385,6 +401,12 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
   };
   handleStopLoggingRef.current = handleStopLogging;
 
+  const handleDiscard = () => {
+    setHeldLogs(null);
+    setViewState('form');
+    setIsOpen(false);
+  };
+
   const handleSubmitReport = async (debugLogs: string) => {
     setViewState('submitting');
     try {
@@ -398,6 +420,7 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
       if (result.success) {
         setIssueUrl(result.issue_url || null);
         setIssueNumber(result.issue_number || null);
+        setHeldLogs(null);
         setViewState('success');
       } else {
         setErrorMessage(result.message);
@@ -688,7 +711,7 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
                     {/* Step 3: Upcoming */}
                     <div className="flex items-center gap-3">
                       <Circle className="w-5 h-5 text-gray-300 dark:text-gray-600 flex-shrink-0" />
-                      <span className="text-sm text-gray-400 dark:text-gray-500">{t('bugReport.stepStopLogging')}</span>
+                      <span className="text-sm text-gray-400 dark:text-gray-500">{t('bugReport.stepReview')}</span>
                     </div>
                   </div>
 
@@ -701,13 +724,39 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
                     <p className="text-xs text-gray-500 dark:text-gray-400 mt-2">{t('bugReport.closeKeepsRecording')}</p>
                   </div>
 
-                  {/* Stop & Submit button */}
+                  {/* Stop button */}
                   <div className="flex justify-center">
                     <button
                       onClick={handleStopLogging}
                       className="px-6 py-2.5 text-sm font-medium text-white bg-red-500 hover:bg-red-600 rounded-lg transition-colors"
                     >
-                      {t('bugReport.stopAndSubmit')}
+                      {t('bugReport.stopLogging')}
+                    </button>
+                  </div>
+                </div>
+              )}
+
+              {viewState === 'review' && heldLogs !== null && (
+                <div data-testid="bug-report-review" className="py-4 space-y-4">
+                  <div className="space-y-2">
+                    <p className="text-sm font-semibold text-gray-900 dark:text-white">{t('bugReport.reviewTitle')}</p>
+                    <p className="text-sm text-gray-600 dark:text-gray-400">{t('bugReport.reviewBody')}</p>
+                    <p className="text-xs text-gray-500 dark:text-gray-400">
+                      {t('bugReport.reviewLogLines', { lines: heldLogs.split('\n').filter((l) => l.trim()).length })}
+                    </p>
+                  </div>
+                  <div className="flex justify-end gap-2">
+                    <button
+                      onClick={handleDiscard}
+                      className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg transition-colors"
+                    >
+                      {t('bugReport.discard')}
+                    </button>
+                    <button
+                      onClick={() => handleSubmitReport(heldLogs)}
+                      className="px-4 py-2 text-sm font-medium text-white bg-red-500 hover:bg-red-600 rounded-lg transition-colors"
+                    >
+                      {t('bugReport.submit')}
                     </button>
                   </div>
                 </div>
@@ -717,7 +766,7 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
                 <div className="flex flex-col items-center justify-center py-6 gap-3">
                   <Loader2 className="w-8 h-8 animate-spin text-blue-500" />
                   <p className="text-sm text-gray-600 dark:text-gray-400 text-center">
-                    {viewState === 'stopping' ? t('bugReport.stoppingLogs') : t('bugReport.submitting')}
+                    {viewState === 'stopping' ? t('bugReport.collectingLogs') : t('bugReport.submitting')}
                   </p>
                   {viewState === 'submitting' && (
                     // Diagnostics are run server-side inside the submit call
@@ -766,7 +815,9 @@ export function BugReportBubble({ showTrigger = true, open, onOpenChange, onLogg
                   <p className="text-sm text-gray-600 dark:text-gray-400 text-center">{errorMessage}</p>
                   <div className="flex gap-2 mt-4">
                     <button
-                      onClick={() => setViewState('form')}
+                      // A failed send keeps its logs, so trying again goes back
+                      // to the review rather than to a new recording.
+                      onClick={() => setViewState(heldLogs !== null ? 'review' : 'form')}
                       className="px-4 py-2 text-sm font-medium text-white bg-red-500 hover:bg-red-600 rounded-lg transition-colors"
                     >
                       {t('bugReport.submit')}

+ 1 - 1
frontend/src/components/Layout.tsx

@@ -1033,7 +1033,7 @@ export function Layout() {
                 )}
               </span>
               {/* A run started from the bug-report panel ends at that panel's
-                  Stop & Submit button, so send the user back there rather than
+                  Stop Logging button, so send the user back there rather than
                   to the System page's raw toggle, which would drop the logs
                   and the description they already wrote (#2847). */}
               {bugReportLogging && (

+ 7 - 3
frontend/src/i18n/locales/de.ts

@@ -7719,11 +7719,15 @@ export default {
     startLogging: 'Debug-Protokollierung starten',
     stepEnableLogging: 'Debug-Protokollierung aktiviert',
     stepReproduce: 'Problem jetzt reproduzieren',
-    stepStopLogging: 'Stoppen & Bericht senden',
-    stopAndSubmit: 'Stoppen & Senden',
+    stepReview: 'Logging stoppen und Bericht prüfen',
+    stopLogging: 'Logging stoppen',
     maxDuration: 'Stoppt automatisch nach {{minutes}} Min.',
-    stoppingLogs: 'Protokolle sammeln & senden...',
+    collectingLogs: 'Protokolle werden gesammelt...',
     submitting: 'Fehlerbericht wird gesendet...',
+    reviewTitle: 'Noch wurde nichts gesendet',
+    reviewBody: 'Beim Senden wird ein öffentliches Issue auf GitHub mit Ihrer Beschreibung, dem Screenshot und der E-Mail (falls angegeben), den Systeminformationen und den gesammelten Protokollen erstellt.',
+    reviewLogLines: 'Gesammelte Protokollzeilen: {{lines}}',
+    discard: 'Verwerfen',
     submittingStepConnection: 'Drucker-Verbindungsprüfungen werden ausgeführt',
     submittingStepVirtualPrinters: 'Setup-Prüfungen für virtuelle Drucker werden ausgeführt',
     submittingStepLogScan: 'Aktuelle Protokolle werden auf bekannte Probleme überprüft',

+ 7 - 3
frontend/src/i18n/locales/en.ts

@@ -7770,11 +7770,15 @@ export default {
     startLogging: 'Start Debug Logging',
     stepEnableLogging: 'Debug logging enabled',
     stepReproduce: 'Reproduce the issue now',
-    stepStopLogging: 'Stop & submit report',
-    stopAndSubmit: 'Stop & Submit',
+    stepReview: 'Stop logging and review the report',
+    stopLogging: 'Stop Logging',
     maxDuration: 'Auto-stops after {{minutes}} min',
-    stoppingLogs: 'Collecting logs & submitting...',
+    collectingLogs: 'Collecting logs...',
     submitting: 'Submitting bug report...',
+    reviewTitle: 'Nothing has been sent yet',
+    reviewBody: 'Submitting posts a public issue on GitHub with your description, the screenshot and email if you added them, the system information and the collected logs.',
+    reviewLogLines: 'Log lines collected: {{lines}}',
+    discard: 'Discard',
     submittingStepConnection: 'Running printer connectivity checks',
     submittingStepVirtualPrinters: 'Running virtual-printer setup checks',
     submittingStepLogScan: 'Scanning recent logs for known issues',

+ 7 - 3
frontend/src/i18n/locales/es.ts

@@ -7727,11 +7727,15 @@ export default {
     startLogging: 'Iniciar el registro de depuración',
     stepEnableLogging: 'Registro de depuración activado',
     stepReproduce: 'Reproduzca el problema ahora',
-    stepStopLogging: 'Detener y enviar el informe',
-    stopAndSubmit: 'Detener y enviar',
+    stepReview: 'Detener el registro y revisar el informe',
+    stopLogging: 'Detener registro',
     maxDuration: 'Se detiene automáticamente tras {{minutes}} min',
-    stoppingLogs: 'Recopilando registros y enviando...',
+    collectingLogs: 'Recopilando registros...',
     submitting: 'Enviando el informe de error...',
+    reviewTitle: 'Todavía no se ha enviado nada',
+    reviewBody: 'Al enviarlo se publica una incidencia pública en GitHub con tu descripción, la captura de pantalla y el correo si los añadiste, la información del sistema y los registros recopilados.',
+    reviewLogLines: 'Líneas de registro recopiladas: {{lines}}',
+    discard: 'Descartar',
     submittingStepConnection: 'Ejecutando comprobaciones de conectividad de impresoras',
     submittingStepVirtualPrinters: 'Ejecutando comprobaciones de configuración de impresoras virtuales',
     submittingStepLogScan: 'Analizando los registros recientes en busca de problemas conocidos',

+ 7 - 3
frontend/src/i18n/locales/fr.ts

@@ -7707,11 +7707,15 @@ export default {
     startLogging: 'Lancer la journalisation',
     stepEnableLogging: 'Journalisation activée',
     stepReproduce: 'Reproduisez le problème',
-    stepStopLogging: 'Arrêter & envoyer',
-    stopAndSubmit: 'Arrêter & Envoyer',
+    stepReview: 'Arrêter la journalisation et vérifier le rapport',
+    stopLogging: 'Arrêter la journalisation',
     maxDuration: 'Arrêt auto après {{minutes}} min',
-    stoppingLogs: 'Collecte des journaux & envoi...',
+    collectingLogs: 'Collecte des journaux...',
     submitting: 'Envoi du rapport de bug...',
+    reviewTitle: 'Rien n\'a encore été envoyé',
+    reviewBody: 'L\'envoi publie une issue publique sur GitHub avec votre description, la capture d\'écran et l\'e-mail si vous les avez ajoutés, les informations système et les journaux collectés.',
+    reviewLogLines: 'Lignes de journal collectées : {{lines}}',
+    discard: 'Abandonner',
     submittingStepConnection: 'Vérification de la connectivité des imprimantes',
     submittingStepVirtualPrinters: 'Vérification de la configuration des imprimantes virtuelles',
     submittingStepLogScan: 'Analyse des journaux récents pour les problèmes connus',

+ 7 - 3
frontend/src/i18n/locales/it.ts

@@ -7706,11 +7706,15 @@ export default {
     startLogging: 'Avvia registrazione debug',
     stepEnableLogging: 'Registrazione debug attivata',
     stepReproduce: 'Riproduci il problema ora',
-    stepStopLogging: 'Ferma & invia rapporto',
-    stopAndSubmit: 'Ferma & Invia',
+    stepReview: 'Ferma il logging e controlla il rapporto',
+    stopLogging: 'Ferma logging',
     maxDuration: 'Arresto automatico dopo {{minutes}} min',
-    stoppingLogs: 'Raccolta log & invio...',
+    collectingLogs: 'Raccolta log...',
     submitting: 'Invio segnalazione bug...',
+    reviewTitle: 'Non è stato ancora inviato nulla',
+    reviewBody: 'L\'invio pubblica una issue pubblica su GitHub con la tua descrizione, lo screenshot e l\'email se li hai aggiunti, le informazioni di sistema e i log raccolti.',
+    reviewLogLines: 'Righe di log raccolte: {{lines}}',
+    discard: 'Scarta',
     submittingStepConnection: 'Controlli di connettività delle stampanti in corso',
     submittingStepVirtualPrinters: 'Controlli di configurazione delle stampanti virtuali in corso',
     submittingStepLogScan: 'Analisi dei log recenti per problemi noti',

+ 7 - 3
frontend/src/i18n/locales/ja.ts

@@ -7720,11 +7720,15 @@ export default {
     startLogging: 'デバッグログ開始',
     stepEnableLogging: 'デバッグログ有効',
     stepReproduce: '問題を再現してください',
-    stepStopLogging: '停止してレポート送信',
-    stopAndSubmit: '停止して送信',
+    stepReview: 'ログ記録を停止してレポートを確認',
+    stopLogging: 'ログ記録を停止',
     maxDuration: '{{minutes}}分後に自動停止',
-    stoppingLogs: 'ログ収集・送信中...',
+    collectingLogs: 'ログを収集中...',
     submitting: 'バグレポートを送信中...',
+    reviewTitle: 'まだ何も送信されていません',
+    reviewBody: '送信すると、説明、追加した場合はスクリーンショットとメールアドレス、システム情報、収集したログを含む公開 Issue が GitHub に作成されます。',
+    reviewLogLines: '収集したログ行数: {{lines}}',
+    discard: '破棄',
     submittingStepConnection: 'プリンターの接続確認を実行中',
     submittingStepVirtualPrinters: '仮想プリンターのセットアップ確認を実行中',
     submittingStepLogScan: '最近のログから既知の問題をスキャン中',

+ 7 - 3
frontend/src/i18n/locales/ko.ts

@@ -7163,11 +7163,15 @@ export default {
     startLogging: '디버그 로깅 시작',
     stepEnableLogging: '디버그 로깅 활성화됨',
     stepReproduce: '이제 문제를 재현하세요',
-    stepStopLogging: '중지 후 보고서 제출',
-    stopAndSubmit: '중지 후 제출',
+    stepReview: '로그 기록 중지 후 보고서 검토',
+    stopLogging: '로그 기록 중지',
     maxDuration: '{{minutes}}분 후 자동 중지',
-    stoppingLogs: '로그 수집 및 제출 중...',
+    collectingLogs: '로그 수집 중...',
     submitting: '버그 보고서 제출 중...',
+    reviewTitle: '아직 아무것도 전송되지 않았습니다',
+    reviewBody: '제출하면 설명, 추가한 경우 스크린샷과 이메일, 시스템 정보, 수집된 로그가 포함된 공개 이슈가 GitHub에 생성됩니다.',
+    reviewLogLines: '수집된 로그 줄 수: {{lines}}',
+    discard: '취소',
     submitSuccess: '버그 보고서가 성공적으로 제출되었습니다!',
     submitFailed: '버그 보고서 제출 실패',
     thankYou: '감사합니다!',

+ 7 - 3
frontend/src/i18n/locales/nl.ts

@@ -7768,11 +7768,15 @@ export default {
     startLogging: 'Debuglogging starten',
     stepEnableLogging: 'Debuglogging ingeschakeld',
     stepReproduce: 'Reproduceer het probleem nu',
-    stepStopLogging: 'Stoppen en rapport verzenden',
-    stopAndSubmit: 'Stoppen en verzenden',
+    stepReview: 'Logging stoppen en rapport controleren',
+    stopLogging: 'Logging stoppen',
     maxDuration: 'Stopt automatisch na {{minutes}} min',
-    stoppingLogs: 'Logs verzamelen en verzenden...',
+    collectingLogs: 'Logs verzamelen...',
     submitting: 'Bugrapport verzenden...',
+    reviewTitle: 'Er is nog niets verzonden',
+    reviewBody: 'Verzenden plaatst een openbaar issue op GitHub met je beschrijving, de schermafbeelding en het e-mailadres als je die hebt toegevoegd, de systeeminformatie en de verzamelde logs.',
+    reviewLogLines: 'Verzamelde logregels: {{lines}}',
+    discard: 'Verwerpen',
     submittingStepConnection: 'Printerverbindingscontroles uitvoeren',
     submittingStepVirtualPrinters: 'Installatiecontroles virtuele printer uitvoeren',
     submittingStepLogScan: 'Recente logboeken scannen op bekende problemen',

+ 7 - 3
frontend/src/i18n/locales/pt-BR.ts

@@ -7706,11 +7706,15 @@ export default {
     startLogging: 'Iniciar log de depuração',
     stepEnableLogging: 'Log de depuração ativado',
     stepReproduce: 'Reproduza o problema agora',
-    stepStopLogging: 'Parar & enviar relatório',
-    stopAndSubmit: 'Parar & Enviar',
+    stepReview: 'Parar o log e revisar o relatório',
+    stopLogging: 'Parar log',
     maxDuration: 'Para automaticamente após {{minutes}} min',
-    stoppingLogs: 'Coletando logs & enviando...',
+    collectingLogs: 'Coletando logs...',
     submitting: 'Enviando relatório de bug...',
+    reviewTitle: 'Nada foi enviado ainda',
+    reviewBody: 'Enviar publica uma issue pública no GitHub com sua descrição, a captura de tela e o email se você os adicionou, as informações do sistema e os logs coletados.',
+    reviewLogLines: 'Linhas de log coletadas: {{lines}}',
+    discard: 'Descartar',
     submittingStepConnection: 'Executando verificações de conectividade das impressoras',
     submittingStepVirtualPrinters: 'Executando verificações de configuração das impressoras virtuais',
     submittingStepLogScan: 'Analisando registros recentes em busca de problemas conhecidos',

+ 7 - 3
frontend/src/i18n/locales/ru.ts

@@ -7344,11 +7344,15 @@ export default {
     startLogging: "Начать отладочную запись",
     stepEnableLogging: "Отладочная запись включена",
     stepReproduce: "Теперь воспроизведите проблему",
-    stepStopLogging: "Остановить и отправить отчёт",
-    stopAndSubmit: "Остановить и отправить",
+    stepReview: "Остановить журналирование и проверить отчёт",
+    stopLogging: "Остановить журналирование",
     maxDuration: "Автоматическая остановка через {{minutes}} мин",
-    stoppingLogs: "Сбор журналов и отправка...",
+    collectingLogs: "Сбор журналов...",
     submitting: "Отправка отчёта об ошибке...",
+    reviewTitle: "Пока ничего не отправлено",
+    reviewBody: "При отправке на GitHub создаётся публичное issue с вашим описанием, снимком экрана и email, если вы их добавили, системной информацией и собранными журналами.",
+    reviewLogLines: "Собрано строк журнала: {{lines}}",
+    discard: "Отменить",
     submittingStepConnection: "Проверка подключений к принтерам",
     submittingStepVirtualPrinters: "Проверка настройки виртуальных принтеров",
     submittingStepLogScan: "Поиск известных проблем в последних журналах",

+ 7 - 3
frontend/src/i18n/locales/sv.ts

@@ -7766,11 +7766,15 @@ errors: {
     startLogging: 'Starta felsökningsloggning',
     stepEnableLogging: 'Felsökningsloggning aktiverad',
     stepReproduce: 'Återskapa problemet nu',
-    stepStopLogging: 'Stoppa och skicka in rapport',
-    stopAndSubmit: 'Stoppa och skicka in',
+    stepReview: 'Stoppa loggningen och granska rapporten',
+    stopLogging: 'Stoppa loggning',
     maxDuration: 'Stoppar automatiskt efter {{minutes}} min',
-    stoppingLogs: 'Samlar in loggar och skickar in...',
+    collectingLogs: 'Samlar in loggar...',
     submitting: 'Skickar in felrapport...',
+    reviewTitle: 'Inget har skickats ännu',
+    reviewBody: 'Att skicka in publicerar ett offentligt ärende på GitHub med din beskrivning, skärmbilden och e-postadressen om du lade till dem, systeminformationen och de insamlade loggarna.',
+    reviewLogLines: 'Insamlade loggrader: {{lines}}',
+    discard: 'Kasta',
     submittingStepConnection: 'Kör skrivaranslutningskontroller',
     submittingStepVirtualPrinters: 'Kör inställningskontroller för virtuella skrivare',
     submittingStepLogScan: 'Söker i senaste loggar efter kända problem',

+ 7 - 3
frontend/src/i18n/locales/tr.ts

@@ -7656,11 +7656,15 @@ export default {
     startLogging: 'Hata Ayıklama Kaydını Başlat',
     stepEnableLogging: 'Hata ayıklama kaydı etkin',
     stepReproduce: 'Sorunu şimdi yeniden oluşturun',
-    stepStopLogging: 'Durdur ve raporu gönder',
-    stopAndSubmit: 'Durdur ve Gönder',
+    stepReview: 'Günlüğü durdur ve raporu gözden geçir',
+    stopLogging: 'Günlüğü Durdur',
     maxDuration: '{{minutes}} dk sonra otomatik durur',
-    stoppingLogs: 'Günlükler toplanıyor ve gönderiliyor...',
+    collectingLogs: 'Günlükler toplanıyor...',
     submitting: 'Hata raporu gönderiliyor...',
+    reviewTitle: 'Henüz hiçbir şey gönderilmedi',
+    reviewBody: 'Göndermek, açıklamanız, eklediyseniz ekran görüntüsü ve e-posta adresiniz, sistem bilgileri ve toplanan günlüklerle GitHub\'da herkese açık bir issue oluşturur.',
+    reviewLogLines: 'Toplanan günlük satırı: {{lines}}',
+    discard: 'Vazgeç',
     submittingStepConnection: 'Yazıcı bağlantı kontrolleri çalıştırılıyor',
     submittingStepVirtualPrinters: 'Sanal yazıcı kurulum kontrolleri çalıştırılıyor',
     submittingStepLogScan: 'Son günlüklerde bilinen sorunlar taranıyor',

+ 7 - 3
frontend/src/i18n/locales/uk.ts

@@ -7758,11 +7758,15 @@ export default {
     startLogging: "Розпочати журнал налагодження",
     stepEnableLogging: "Журнал налагодження ввімкнено",
     stepReproduce: "Відтворіть проблему зараз",
-    stepStopLogging: "Зупинити та подати звіт",
-    stopAndSubmit: "Зупинити та надіслати",
+    stepReview: "Зупинити журналювання та переглянути звіт",
+    stopLogging: "Зупинити журналювання",
     maxDuration: "Автоматична зупинка через {{minutes}} хв",
-    stoppingLogs: "Збір журналів і надсилання...",
+    collectingLogs: "Збір журналів...",
     submitting: "Надсилання звіту про помилку...",
+    reviewTitle: "Ще нічого не надіслано",
+    reviewBody: "Надсилання створює публічне issue на GitHub з вашим описом, знімком екрана та email, якщо ви їх додали, системною інформацією та зібраними журналами.",
+    reviewLogLines: "Зібрано рядків журналу: {{lines}}",
+    discard: "Відхилити",
     submittingStepConnection: "Запуск перевірки підключення принтера",
     submittingStepVirtualPrinters: "Виконання перевірок налаштування віртуального принтера",
     submittingStepLogScan: "Сканування останніх журналів на наявність відомих проблем",

+ 7 - 3
frontend/src/i18n/locales/zh-CN.ts

@@ -7704,11 +7704,15 @@ export default {
     startLogging: '开始调试日志',
     stepEnableLogging: '调试日志已启用',
     stepReproduce: '请现在重现问题',
-    stepStopLogging: '停止并提交报告',
-    stopAndSubmit: '停止并提交',
+    stepReview: '停止日志记录并检查报告',
+    stopLogging: '停止日志记录',
     maxDuration: '{{minutes}}分钟后自动停止',
-    stoppingLogs: '正在收集日志并提交...',
+    collectingLogs: '正在收集日志...',
     submitting: '正在提交错误报告...',
+    reviewTitle: '尚未发送任何内容',
+    reviewBody: '提交后将在 GitHub 上创建一个公开 issue,包含您的描述、您添加的截图和邮箱、系统信息和收集的日志。',
+    reviewLogLines: '已收集日志行数:{{lines}}',
+    discard: '放弃',
     submittingStepConnection: '正在执行打印机连接性检查',
     submittingStepVirtualPrinters: '正在执行虚拟打印机设置检查',
     submittingStepLogScan: '正在扫描最近的日志以查找已知问题',

+ 7 - 3
frontend/src/i18n/locales/zh-TW.ts

@@ -7704,11 +7704,15 @@ export default {
     startLogging: '開始偵錯日誌',
     stepEnableLogging: '偵錯日誌已啟用',
     stepReproduce: '請現在重現問題',
-    stepStopLogging: '停止並提交報告',
-    stopAndSubmit: '停止並提交',
+    stepReview: '停止日誌記錄並檢查報告',
+    stopLogging: '停止日誌記錄',
     maxDuration: '{{minutes}} 分鐘後自動停止',
-    stoppingLogs: '正在收集日誌並提交...',
+    collectingLogs: '正在收集日誌...',
     submitting: '正在提交錯誤報告...',
+    reviewTitle: '尚未傳送任何內容',
+    reviewBody: '提交後將在 GitHub 上建立一個公開 issue,包含您的描述、您新增的截圖和電子郵件、系統資訊和收集的日誌。',
+    reviewLogLines: '已收集日誌行數:{{lines}}',
+    discard: '捨棄',
     submittingStepConnection: '正在執行印表機連線檢查',
     submittingStepVirtualPrinters: '正在執行虛擬印表機設定檢查',
     submittingStepLogScan: '正在掃描最近的日誌以尋找已知問題',