Browse Source

fix(settings): remove the "Save thumbnails" and "Notification Language" controls, which nothing read (the API keeps both fields); a SQLite-to-PostgreSQL restore fills empty required timestamps in UTC instead of the host's local time

maziggy 2 days ago
parent
commit
a10d5430de

+ 2 - 0
CHANGELOG.md

@@ -164,6 +164,8 @@ 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.
 - **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
 ### Fixed
+- **Settings: removed "Save thumbnails" and "Notification Language", which did nothing** — Nothing read either: thumbnails were always stored, and notifications always used their template text as written. The API still accepts both fields.
+- **Restoring an old SQLite backup onto PostgreSQL could put some timestamps hours off** — Required timestamps the backup left empty were filled with the host's local time, while every other timestamp is stored in UTC, so on a host ahead of UTC those rows appeared hours in the future. They are now filled in UTC.
 - **Maintenance: a printer's time offline was counted as print time** — A printer that dropped off mid-print and came back printing hours later had the whole gap added to its runtime, so hours-based maintenance came due early. Time while Bambuddy itself was restarting is still counted, as before.
 - **Maintenance: a printer's time offline was counted as print time** — A printer that dropped off mid-print and came back printing hours later had the whole gap added to its runtime, so hours-based maintenance came due early. Time while Bambuddy itself was restarting is still counted, as before.
 - **Maintenance: duplicate maintenance items** — A printer's items are created when its maintenance is first shown, and two pages (or a page and the background check) could each create the same one; marking it performed could then update the copy not shown, and assigning that type again failed. Existing duplicates are merged on upgrade (the most recently performed one is kept, or the one the page showed when none was, with the history of all), and they can no longer be created.
 - **Maintenance: duplicate maintenance items** — A printer's items are created when its maintenance is first shown, and two pages (or a page and the background check) could each create the same one; marking it performed could then update the copy not shown, and assigning that type again failed. Existing duplicates are merged on upgrade (the most recently performed one is kept, or the one the page showed when none was, with the history of all), and they can no longer be created.
 - **Maintenance API: "performed" answered in hours for an item set to days** — Its response used the maintenance type's interval type instead of the item's own setting, which the list already used.
 - **Maintenance API: "performed" answered in hours for an item set to days** — Its response used the maintenance type's interval type instead of the item's own setting, which the list already used.

+ 4 - 2
backend/app/api/routes/settings.py

@@ -1333,7 +1333,7 @@ async def _import_sqlite_to_postgres(sqlite_path: Path):
 
 
                 # Identify columns that need type conversion (SQLite stores booleans
                 # Identify columns that need type conversion (SQLite stores booleans
                 # as int and datetimes as str — asyncpg requires native Python types)
                 # as int and datetimes as str — asyncpg requires native Python types)
-                from datetime import datetime as dt
+                from datetime import datetime as dt, timezone
 
 
                 bool_columns = set()
                 bool_columns = set()
                 datetime_columns = set()
                 datetime_columns = set()
@@ -1365,7 +1365,9 @@ async def _import_sqlite_to_postgres(sqlite_path: Path):
                                     if sd is not None:
                                     if sd is not None:
                                         not_null_defaults[col.name] = sd
                                         not_null_defaults[col.name] = sd
 
 
-                now = dt.now()
+                # Naive UTC, as every stored timestamp is: the host's local
+                # time put backfilled rows hours off (DB-C4).
+                now = dt.now(timezone.utc).replace(tzinfo=None)
                 value_fixes = _restored_value_fixes(table_name)
                 value_fixes = _restored_value_fixes(table_name)
 
 
                 def _convert_row(
                 def _convert_row(

+ 37 - 0
backend/tests/unit/test_restore_schema_compat.py

@@ -304,3 +304,40 @@ def test_the_manifest_is_read(tmp_path):
     (tmp_path / "manifest.json").write_text('{"format": 1, "app_version": "1.2.7"}')
     (tmp_path / "manifest.json").write_text('{"format": 1, "app_version": "1.2.7"}')
 
 
     assert _read_backup_manifest(tmp_path)["app_version"] == "1.2.7"
     assert _read_backup_manifest(tmp_path)["app_version"] == "1.2.7"
+
+
+@pytest.mark.asyncio
+async def test_an_empty_required_timestamp_is_filled_with_utc_now(tmp_path):
+    """DB-C4: every stored timestamp is naive UTC, but an empty required one
+    in an old backup was filled with the host's local time -- on a Berlin host
+    1-2 h in the future. The host here is 14 h ahead of UTC."""
+    import os
+    import time
+    from datetime import datetime, timezone
+
+    path = _source(
+        tmp_path,
+        "CREATE TABLE cost_centers (id INTEGER PRIMARY KEY, code TEXT, name TEXT, created_at TEXT, updated_at TEXT)",
+        ["INSERT INTO cost_centers (id, code, name, created_at, updated_at) VALUES (1, 'abc', 'Lab', NULL, NULL)"],
+    )
+    from backend.app.api.routes import settings as settings_module
+
+    before = os.environ.get("TZ")
+    os.environ["TZ"] = "Pacific/Kiritimati"
+    time.tzset()
+    try:
+        engine, executed = _mock_engine()
+        with patch("backend.app.core.database._create_engine", new=MagicMock(return_value=engine)):
+            await settings_module._import_sqlite_to_postgres(path)
+    finally:
+        # Back to the zone the process had, whatever it was.
+        if before is None:
+            os.environ.pop("TZ", None)
+        else:
+            os.environ["TZ"] = before
+        time.tzset()
+
+    params = next(p for sql, p in executed if sql.startswith("INSERT INTO cost_centers"))[0]
+    utc_now = datetime.now(timezone.utc).replace(tzinfo=None)
+    assert params["created_at"].tzinfo is None
+    assert abs((params["created_at"] - utc_now).total_seconds()) < 120

+ 34 - 0
frontend/src/__tests__/pages/SettingsPageUnsavedFields.test.tsx

@@ -123,3 +123,37 @@ describe('SettingsPage printer temperature history retention', () => {
     });
     });
   });
   });
 });
 });
+
+/**
+ * settings-2 / settings-3: "Save thumbnails" and "Notification Language" were
+ * saved but nothing read them -- thumbnails were always stored, notifications
+ * always used their template text. The controls are gone; the API keeps the
+ * fields for scripts that send them.
+ */
+describe('SettingsPage controls that did nothing', () => {
+  beforeEach(() => {
+    window.history.replaceState({}, '', '/');
+    vi.mocked(localStorage.getItem).mockReset();
+    localStorage.clear();
+    setAuthToken(null);
+    server.use(
+      http.get('/api/v1/settings/', () => HttpResponse.json(settings)),
+      http.get('/api/v1/auth/status', () => HttpResponse.json({ auth_enabled: false, requires_setup: false })),
+    );
+  });
+
+  it('has no "Save thumbnails" toggle', async () => {
+    render(<SettingsPage />);
+    expect(await screen.findByText('Capture finish photo')).toBeInTheDocument();
+    expect(screen.queryByText('Save thumbnails')).not.toBeInTheDocument();
+  });
+
+  it('has no notification language picker', async () => {
+    const user = userEvent.setup();
+    render(<SettingsPage />);
+    await screen.findByText('Date Format');
+    await user.click(screen.getAllByText('Notifications')[0]);
+    expect(await screen.findByRole('button', { name: /^Add$/ }, { timeout: 3000 })).toBeInTheDocument();
+    expect(screen.queryByText('Notification Language')).not.toBeInTheDocument();
+  });
+});

+ 0 - 4
frontend/src/i18n/locales/de.ts

@@ -2185,8 +2185,6 @@ export default {
     upToDate: 'Sie sind auf dem neuesten Stand',
     upToDate: 'Sie sind auf dem neuesten Stand',
     updateAvailable: 'Update verfügbar',
     updateAvailable: 'Update verfügbar',
     // Notifications
     // Notifications
-    notificationLanguage: 'Benachrichtigungssprache',
-    notificationLanguageDescription: 'Sprache für Push-Benachrichtigungen',
     bedCooledThreshold: 'Bett-Abkühlung Schwellenwert',
     bedCooledThreshold: 'Bett-Abkühlung Schwellenwert',
     bedCooledThresholdDescription: 'Temperatur, unter der das Bett nach einem Druck als abgekühlt gilt',
     bedCooledThresholdDescription: 'Temperatur, unter der das Bett nach einem Druck als abgekühlt gilt',
     userNotificationsEnabled: 'Benutzerbenachrichtigungen',
     userNotificationsEnabled: 'Benutzerbenachrichtigungen',
@@ -2313,7 +2311,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'Seitenleisten-Reihenfolge',
     sidebarOrder: 'Seitenleisten-Reihenfolge',
     // Camera
     // Camera
-    saveThumbnails: 'Vorschaubilder speichern',
     captureFinishPhoto: 'Abschlussfoto aufnehmen',
     captureFinishPhoto: 'Abschlussfoto aufnehmen',
     noPrintersConfigured: 'Keine Drucker konfiguriert',
     noPrintersConfigured: 'Keine Drucker konfiguriert',
     // Updates
     // Updates
@@ -2857,7 +2854,6 @@ export default {
     // Archive
     // Archive
     autoArchivePrints: 'Drucke automatisch archivieren',
     autoArchivePrints: 'Drucke automatisch archivieren',
     autoArchiveDescription: '3MF-Dateien automatisch speichern, wenn Drucke abgeschlossen sind. Aus: Kein Drucker archiviert Drucke, die außerhalb von Bambuddy gestartet wurden.',
     autoArchiveDescription: '3MF-Dateien automatisch speichern, wenn Drucke abgeschlossen sind. Aus: Kein Drucker archiviert Drucke, die außerhalb von Bambuddy gestartet wurden.',
-    saveThumbnailsDescription: 'Vorschaubilder aus 3MF-Dateien extrahieren und speichern',
     captureFinishPhotoDescription: 'Foto von der Druckerkamera aufnehmen, wenn der Druck abgeschlossen ist. Bambuddy zeichnet während des Drucks einen kurzen Zeitraffer auf, damit das Foto aus dem Moment vor dem Absenken der Druckplatte stammen kann. Die Zeitraffer-Datei bleibt erhalten, wenn du den Zeitraffer für diesen Druck aktiviert hast, andernfalls wird sie nach Aufnahme des Fotos automatisch gelöscht.',
     captureFinishPhotoDescription: 'Foto von der Druckerkamera aufnehmen, wenn der Druck abgeschlossen ist. Bambuddy zeichnet während des Drucks einen kurzen Zeitraffer auf, damit das Foto aus dem Moment vor dem Absenken der Druckplatte stammen kann. Die Zeitraffer-Datei bleibt erhalten, wenn du den Zeitraffer für diesen Druck aktiviert hast, andernfalls wird sie nach Aufnahme des Fotos automatisch gelöscht.',
     finishPhotoRestorePlate: 'Druckplatte für Abschlussfoto anheben',
     finishPhotoRestorePlate: 'Druckplatte für Abschlussfoto anheben',
     finishPhotoRestorePlateDescription: 'Der Drucker senkt die Druckplatte am Druckende um etwa 100 mm ab, wodurch der fertige Druck unterhalb des Kamerabildausschnitts liegt. Bambuddy hebt sie wieder bis knapp über die zuletzt gedruckte Schicht an, nimmt das Foto auf und senkt sie danach wieder ab. Wird übersprungen, wenn die Druckhöhe unbekannt ist oder ein weiterer Auftrag in der Warteschlange steht.',
     finishPhotoRestorePlateDescription: 'Der Drucker senkt die Druckplatte am Druckende um etwa 100 mm ab, wodurch der fertige Druck unterhalb des Kamerabildausschnitts liegt. Bambuddy hebt sie wieder bis knapp über die zuletzt gedruckte Schicht an, nimmt das Foto auf und senkt sie danach wieder ab. Wird übersprungen, wenn die Druckhöhe unbekannt ist oder ein weiterer Auftrag in der Warteschlange steht.',

+ 0 - 4
frontend/src/i18n/locales/en.ts

@@ -2207,8 +2207,6 @@ export default {
     upToDate: 'You are up to date',
     upToDate: 'You are up to date',
     updateAvailable: 'Update available',
     updateAvailable: 'Update available',
     // Notifications
     // Notifications
-    notificationLanguage: 'Notification Language',
-    notificationLanguageDescription: 'Language for push notifications',
     bedCooledThreshold: 'Bed Cooled Threshold',
     bedCooledThreshold: 'Bed Cooled Threshold',
     bedCooledThresholdDescription: 'Temperature below which the bed is considered cooled after a print',
     bedCooledThresholdDescription: 'Temperature below which the bed is considered cooled after a print',
     userNotificationsEnabled: 'User Notifications',
     userNotificationsEnabled: 'User Notifications',
@@ -2335,7 +2333,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'Sidebar order',
     sidebarOrder: 'Sidebar order',
     // Camera
     // Camera
-    saveThumbnails: 'Save thumbnails',
     captureFinishPhoto: 'Capture finish photo',
     captureFinishPhoto: 'Capture finish photo',
     noPrintersConfigured: 'No printers configured',
     noPrintersConfigured: 'No printers configured',
     // Updates
     // Updates
@@ -2879,7 +2876,6 @@ export default {
     // Archive
     // Archive
     autoArchivePrints: 'Auto-archive prints',
     autoArchivePrints: 'Auto-archive prints',
     autoArchiveDescription: 'Automatically save 3MF files when prints complete. When off, no printer archives prints started outside Bambuddy.',
     autoArchiveDescription: 'Automatically save 3MF files when prints complete. When off, no printer archives prints started outside Bambuddy.',
-    saveThumbnailsDescription: 'Extract and save preview images from 3MF files',
     captureFinishPhotoDescription: 'Take a photo from printer camera when print completes. Bambuddy records a brief timelapse during the print so the photo can be sourced from the moment before the bed drops; the timelapse file is kept if you enabled timelapse for this print, otherwise it is deleted automatically after the photo is captured.',
     captureFinishPhotoDescription: 'Take a photo from printer camera when print completes. Bambuddy records a brief timelapse during the print so the photo can be sourced from the moment before the bed drops; the timelapse file is kept if you enabled timelapse for this print, otherwise it is deleted automatically after the photo is captured.',
     finishPhotoRestorePlate: 'Restore plate for finish photo',
     finishPhotoRestorePlate: 'Restore plate for finish photo',
     finishPhotoRestorePlateDescription: 'The printer drops the build plate about 100 mm when a print ends, leaving the finished print below the camera\'s framing. Bambuddy raises it back to just above the last printed layer, takes the photo, then lowers it again. Skipped when the print height is unknown or another job is queued.',
     finishPhotoRestorePlateDescription: 'The printer drops the build plate about 100 mm when a print ends, leaving the finished print below the camera\'s framing. Bambuddy raises it back to just above the last printed layer, takes the photo, then lowers it again. Skipped when the print height is unknown or another job is queued.',

+ 0 - 4
frontend/src/i18n/locales/es.ts

@@ -2188,8 +2188,6 @@ export default {
     upToDate: 'Está actualizado',
     upToDate: 'Está actualizado',
     updateAvailable: 'Actualización disponible',
     updateAvailable: 'Actualización disponible',
     // Notifications
     // Notifications
-    notificationLanguage: 'Idioma de las notificaciones',
-    notificationLanguageDescription: 'Idioma de las notificaciones push',
     bedCooledThreshold: 'Umbral de cama enfriada',
     bedCooledThreshold: 'Umbral de cama enfriada',
     bedCooledThresholdDescription: 'Temperatura por debajo de la cual se considera que la cama se ha enfriado tras una impresión',
     bedCooledThresholdDescription: 'Temperatura por debajo de la cual se considera que la cama se ha enfriado tras una impresión',
     userNotificationsEnabled: 'Notificaciones de usuario',
     userNotificationsEnabled: 'Notificaciones de usuario',
@@ -2316,7 +2314,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'Orden de la barra lateral',
     sidebarOrder: 'Orden de la barra lateral',
     // Camera
     // Camera
-    saveThumbnails: 'Guardar miniaturas',
     captureFinishPhoto: 'Capturar foto de finalización',
     captureFinishPhoto: 'Capturar foto de finalización',
     noPrintersConfigured: 'No hay impresoras configuradas',
     noPrintersConfigured: 'No hay impresoras configuradas',
     // Updates
     // Updates
@@ -2859,7 +2856,6 @@ export default {
     // Archive
     // Archive
     autoArchivePrints: 'Archivar impresiones automáticamente',
     autoArchivePrints: 'Archivar impresiones automáticamente',
     autoArchiveDescription: 'Guardar automáticamente los archivos 3MF cuando se completan las impresiones. Desactivado: ninguna impresora archiva las impresiones iniciadas fuera de Bambuddy.',
     autoArchiveDescription: 'Guardar automáticamente los archivos 3MF cuando se completan las impresiones. Desactivado: ninguna impresora archiva las impresiones iniciadas fuera de Bambuddy.',
-    saveThumbnailsDescription: 'Extraer y guardar imágenes de vista previa de los archivos 3MF',
     captureFinishPhotoDescription: 'Tomar una foto desde la cámara de la impresora cuando se completa la impresión. Bambuddy graba un breve timelapse durante la impresión para que la foto pueda obtenerse del momento previo al descenso de la cama; el archivo del timelapse se conserva si activaste el timelapse para esta impresión, de lo contrario se elimina automáticamente tras capturar la foto.',
     captureFinishPhotoDescription: 'Tomar una foto desde la cámara de la impresora cuando se completa la impresión. Bambuddy graba un breve timelapse durante la impresión para que la foto pueda obtenerse del momento previo al descenso de la cama; el archivo del timelapse se conserva si activaste el timelapse para esta impresión, de lo contrario se elimina automáticamente tras capturar la foto.',
     finishPhotoRestorePlate: 'Elevar la cama para la foto final',
     finishPhotoRestorePlate: 'Elevar la cama para la foto final',
     finishPhotoRestorePlateDescription: 'La impresora baja la cama unos 100 mm al terminar una impresión, dejando la pieza terminada por debajo del encuadre de la cámara. Bambuddy la vuelve a subir hasta justo encima de la última capa impresa, toma la foto y luego la baja de nuevo. Se omite si se desconoce la altura de la impresión o si hay otro trabajo en cola.',
     finishPhotoRestorePlateDescription: 'La impresora baja la cama unos 100 mm al terminar una impresión, dejando la pieza terminada por debajo del encuadre de la cámara. Bambuddy la vuelve a subir hasta justo encima de la última capa impresa, toma la foto y luego la baja de nuevo. Se omite si se desconoce la altura de la impresión o si hay otro trabajo en cola.',

+ 0 - 4
frontend/src/i18n/locales/fr.ts

@@ -2140,8 +2140,6 @@ export default {
     upToDate: 'Bambuddy est à jour',
     upToDate: 'Bambuddy est à jour',
     updateAvailable: 'Mise à jour disponible',
     updateAvailable: 'Mise à jour disponible',
     // Notifications
     // Notifications
-    notificationLanguage: 'Langue des notifications',
-    notificationLanguageDescription: 'Langue pour les notifications push',
     bedCooledThreshold: 'Seuil de refroidissement du plateau',
     bedCooledThreshold: 'Seuil de refroidissement du plateau',
     bedCooledThresholdDescription: 'Température en dessous de laquelle le plateau est considéré comme refroidi',
     bedCooledThresholdDescription: 'Température en dessous de laquelle le plateau est considéré comme refroidi',
     userNotificationsEnabled: 'Notifications utilisateur',
     userNotificationsEnabled: 'Notifications utilisateur',
@@ -2268,7 +2266,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'Ordre de la barre latérale',
     sidebarOrder: 'Ordre de la barre latérale',
     // Camera
     // Camera
-    saveThumbnails: 'Enregistrer les vignettes',
     captureFinishPhoto: 'Prendre une photo à la fin',
     captureFinishPhoto: 'Prendre une photo à la fin',
     noPrintersConfigured: 'Aucune imprimante configurée',
     noPrintersConfigured: 'Aucune imprimante configurée',
     // Updates
     // Updates
@@ -2810,7 +2807,6 @@ export default {
     progressInTitleDescription: 'Affiche le pourcentage de l\'impression en cours et un anneau de progression dans l\'onglet du navigateur.',
     progressInTitleDescription: 'Affiche le pourcentage de l\'impression en cours et un anneau de progression dans l\'onglet du navigateur.',
     autoArchivePrints: 'Archiver automatiquement les impressions',
     autoArchivePrints: 'Archiver automatiquement les impressions',
     autoArchiveDescription: 'Sauvegarder automatiquement les fichiers 3MF à la fin des impressions. Désactivé : aucune imprimante n\'archive les impressions lancées en dehors de Bambuddy.',
     autoArchiveDescription: 'Sauvegarder automatiquement les fichiers 3MF à la fin des impressions. Désactivé : aucune imprimante n\'archive les impressions lancées en dehors de Bambuddy.',
-    saveThumbnailsDescription: 'Extraire et sauvegarder les images d\'aperçu des fichiers 3MF',
     captureFinishPhotoDescription: 'Prendre une photo avec la caméra de l\'imprimante à la fin de l\'impression. Bambuddy enregistre un court timelapse pendant l\'impression afin que la photo puisse provenir du moment précédant l\'abaissement du plateau ; le fichier du timelapse est conservé si vous avez activé le timelapse pour cette impression, sinon il est supprimé automatiquement après la capture de la photo.',
     captureFinishPhotoDescription: 'Prendre une photo avec la caméra de l\'imprimante à la fin de l\'impression. Bambuddy enregistre un court timelapse pendant l\'impression afin que la photo puisse provenir du moment précédant l\'abaissement du plateau ; le fichier du timelapse est conservé si vous avez activé le timelapse pour cette impression, sinon il est supprimé automatiquement après la capture de la photo.',
     finishPhotoRestorePlate: 'Remonter le plateau pour la photo finale',
     finishPhotoRestorePlate: 'Remonter le plateau pour la photo finale',
     finishPhotoRestorePlateDescription: 'L\'imprimante abaisse le plateau d\'environ 100 mm à la fin d\'une impression, plaçant l\'objet terminé sous le cadrage de la caméra. Bambuddy le remonte juste au-dessus de la dernière couche imprimée, prend la photo, puis le rabaisse. Ignoré si la hauteur d\'impression est inconnue ou si un autre travail est en file d\'attente.',
     finishPhotoRestorePlateDescription: 'L\'imprimante abaisse le plateau d\'environ 100 mm à la fin d\'une impression, plaçant l\'objet terminé sous le cadrage de la caméra. Bambuddy le remonte juste au-dessus de la dernière couche imprimée, prend la photo, puis le rabaisse. Ignoré si la hauteur d\'impression est inconnue ou si un autre travail est en file d\'attente.',

+ 0 - 4
frontend/src/i18n/locales/it.ts

@@ -2140,8 +2140,6 @@ export default {
     upToDate: 'Sei aggiornato',
     upToDate: 'Sei aggiornato',
     updateAvailable: 'Aggiornamento disponibile',
     updateAvailable: 'Aggiornamento disponibile',
     // Notifications
     // Notifications
-    notificationLanguage: 'Lingua notifiche',
-    notificationLanguageDescription: 'Lingua per notifiche push',
     bedCooledThreshold: 'Soglia raffreddamento piatto',
     bedCooledThreshold: 'Soglia raffreddamento piatto',
     bedCooledThresholdDescription: 'Temperatura sotto la quale il piatto è considerato raffreddato dopo una stampa',
     bedCooledThresholdDescription: 'Temperatura sotto la quale il piatto è considerato raffreddato dopo una stampa',
     userNotificationsEnabled: 'Notifiche utente',
     userNotificationsEnabled: 'Notifiche utente',
@@ -2268,7 +2266,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'Ordine barra laterale',
     sidebarOrder: 'Ordine barra laterale',
     // Camera
     // Camera
-    saveThumbnails: 'Salva miniature',
     captureFinishPhoto: 'Acquisisci foto finale',
     captureFinishPhoto: 'Acquisisci foto finale',
     noPrintersConfigured: 'Nessuna stampante configurata',
     noPrintersConfigured: 'Nessuna stampante configurata',
     // Updates
     // Updates
@@ -2809,7 +2806,6 @@ export default {
     progressInTitleDescription: 'Mostra la percentuale della stampa attiva e un anello di avanzamento nella scheda del browser.',
     progressInTitleDescription: 'Mostra la percentuale della stampa attiva e un anello di avanzamento nella scheda del browser.',
     autoArchivePrints: 'Archiviazione automatica stampe',
     autoArchivePrints: 'Archiviazione automatica stampe',
     autoArchiveDescription: 'Salva automaticamente i file 3MF al completamento delle stampe. Disattivato: nessuna stampante archivia le stampe avviate al di fuori di Bambuddy.',
     autoArchiveDescription: 'Salva automaticamente i file 3MF al completamento delle stampe. Disattivato: nessuna stampante archivia le stampe avviate al di fuori di Bambuddy.',
-    saveThumbnailsDescription: 'Estrai e salva le immagini di anteprima dai file 3MF',
     captureFinishPhotoDescription: 'Scatta una foto dalla fotocamera della stampante al completamento della stampa. Bambuddy registra un breve timelapse durante la stampa in modo che la foto possa essere ricavata dal momento precedente all\'abbassamento del piatto; il file del timelapse viene mantenuto se hai abilitato il timelapse per questa stampa, altrimenti viene eliminato automaticamente dopo l\'acquisizione della foto.',
     captureFinishPhotoDescription: 'Scatta una foto dalla fotocamera della stampante al completamento della stampa. Bambuddy registra un breve timelapse durante la stampa in modo che la foto possa essere ricavata dal momento precedente all\'abbassamento del piatto; il file del timelapse viene mantenuto se hai abilitato il timelapse per questa stampa, altrimenti viene eliminato automaticamente dopo l\'acquisizione della foto.',
     finishPhotoRestorePlate: 'Solleva il piatto per la foto finale',
     finishPhotoRestorePlate: 'Solleva il piatto per la foto finale',
     finishPhotoRestorePlateDescription: 'La stampante abbassa il piatto di circa 100 mm al termine di una stampa, lasciando l\'oggetto finito sotto l\'inquadratura della fotocamera. Bambuddy lo risolleva fino a poco sopra l\'ultimo strato stampato, scatta la foto e poi lo riabbassa. Ignorato se l\'altezza di stampa è sconosciuta o se un altro lavoro è in coda.',
     finishPhotoRestorePlateDescription: 'La stampante abbassa il piatto di circa 100 mm al termine di una stampa, lasciando l\'oggetto finito sotto l\'inquadratura della fotocamera. Bambuddy lo risolleva fino a poco sopra l\'ultimo strato stampato, scatta la foto e poi lo riabbassa. Ignorato se l\'altezza di stampa è sconosciuta o se un altro lavoro è in coda.',

+ 0 - 4
frontend/src/i18n/locales/ja.ts

@@ -2184,8 +2184,6 @@ export default {
     upToDate: '最新です',
     upToDate: '最新です',
     updateAvailable: 'アップデートあり',
     updateAvailable: 'アップデートあり',
     // Notifications
     // Notifications
-    notificationLanguage: '通知の言語',
-    notificationLanguageDescription: 'プッシュ通知の言語',
     bedCooledThreshold: 'ベッド冷却しきい値',
     bedCooledThreshold: 'ベッド冷却しきい値',
     bedCooledThresholdDescription: '印刷後にベッドが冷却されたと見なす温度',
     bedCooledThresholdDescription: '印刷後にベッドが冷却されたと見なす温度',
     userNotificationsEnabled: 'ユーザー通知',
     userNotificationsEnabled: 'ユーザー通知',
@@ -2312,7 +2310,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'サイドバーの順序',
     sidebarOrder: 'サイドバーの順序',
     // Camera
     // Camera
-    saveThumbnails: 'サムネイルを保存',
     captureFinishPhoto: '完了写真を撮影',
     captureFinishPhoto: '完了写真を撮影',
     noPrintersConfigured: 'プリンターが設定されていません',
     noPrintersConfigured: 'プリンターが設定されていません',
     // Updates
     // Updates
@@ -2856,7 +2853,6 @@ export default {
     // Archive
     // Archive
     autoArchivePrints: '印刷を自動アーカイブ',
     autoArchivePrints: '印刷を自動アーカイブ',
     autoArchiveDescription: '印刷完了時に3MFファイルを自動保存。オフの場合、Bambuddy 以外から開始された印刷はどのプリンターでもアーカイブされません。',
     autoArchiveDescription: '印刷完了時に3MFファイルを自動保存。オフの場合、Bambuddy 以外から開始された印刷はどのプリンターでもアーカイブされません。',
-    saveThumbnailsDescription: '3MFファイルからプレビュー画像を抽出して保存',
     captureFinishPhotoDescription: '印刷完了時にプリンターカメラから写真を撮影します。Bambuddy は印刷中に短いタイムラプスを記録し、ベッドが下がる前の瞬間から写真を取得できるようにします。この印刷でタイムラプスを有効にしていた場合はタイムラプスファイルが保存され、それ以外の場合は写真の取得後に自動的に削除されます。',
     captureFinishPhotoDescription: '印刷完了時にプリンターカメラから写真を撮影します。Bambuddy は印刷中に短いタイムラプスを記録し、ベッドが下がる前の瞬間から写真を取得できるようにします。この印刷でタイムラプスを有効にしていた場合はタイムラプスファイルが保存され、それ以外の場合は写真の取得後に自動的に削除されます。',
     finishPhotoRestorePlate: '完了写真のためにプレートを戻す',
     finishPhotoRestorePlate: '完了写真のためにプレートを戻す',
     finishPhotoRestorePlateDescription: 'プリンターは印刷終了時にビルドプレートを約 100 mm 下降させるため、完成した造形物がカメラの画角より下に来ます。Bambuddy はプレートを最終印刷レイヤーのすぐ上まで戻して写真を撮影し、その後再び下降させます。造形高さが不明な場合や次のジョブがキューにある場合はスキップされます。',
     finishPhotoRestorePlateDescription: 'プリンターは印刷終了時にビルドプレートを約 100 mm 下降させるため、完成した造形物がカメラの画角より下に来ます。Bambuddy はプレートを最終印刷レイヤーのすぐ上まで戻して写真を撮影し、その後再び下降させます。造形高さが不明な場合や次のジョブがキューにある場合はスキップされます。',

+ 0 - 4
frontend/src/i18n/locales/ko.ts

@@ -2091,8 +2091,6 @@ export default {
     latestVersion: '최신 버전',
     latestVersion: '최신 버전',
     upToDate: '최신 상태입니다',
     upToDate: '최신 상태입니다',
     updateAvailable: '업데이트 가능',
     updateAvailable: '업데이트 가능',
-    notificationLanguage: '알림 언어',
-    notificationLanguageDescription: '푸시 알림 언어',
     bedCooledThreshold: '베드 냉각 임계값',
     bedCooledThreshold: '베드 냉각 임계값',
     bedCooledThresholdDescription: '인쇄 후 베드가 냉각된 것으로 간주되는 온도',
     bedCooledThresholdDescription: '인쇄 후 베드가 냉각된 것으로 간주되는 온도',
     userNotificationsEnabled: '사용자 알림',
     userNotificationsEnabled: '사용자 알림',
@@ -2212,7 +2210,6 @@ export default {
     allPrinters: '모든 프린터',
     allPrinters: '모든 프린터',
     noDefaultPrinter: '기본값 없음 (매번 묻기)',
     noDefaultPrinter: '기본값 없음 (매번 묻기)',
     sidebarOrder: '사이드바 순서',
     sidebarOrder: '사이드바 순서',
-    saveThumbnails: '썸네일 저장',
     captureFinishPhoto: '완료 사진 캡처',
     captureFinishPhoto: '완료 사진 캡처',
     noPrintersConfigured: '설정된 프린터 없음',
     noPrintersConfigured: '설정된 프린터 없음',
     checkForUpdatesLabel: '업데이트 확인',
     checkForUpdatesLabel: '업데이트 확인',
@@ -2721,7 +2718,6 @@ export default {
     progressInTitleDescription: '브라우저 탭에 진행 중인 인쇄의 백분율과 진행 링을 표시합니다.',
     progressInTitleDescription: '브라우저 탭에 진행 중인 인쇄의 백분율과 진행 링을 표시합니다.',
     autoArchivePrints: '인쇄 자동 아카이브',
     autoArchivePrints: '인쇄 자동 아카이브',
     autoArchiveDescription: '인쇄 완료 시 3MF 파일 자동 저장. 끄면 Bambuddy 외부에서 시작된 인쇄는 어떤 프린터에서도 보관되지 않습니다.',
     autoArchiveDescription: '인쇄 완료 시 3MF 파일 자동 저장. 끄면 Bambuddy 외부에서 시작된 인쇄는 어떤 프린터에서도 보관되지 않습니다.',
-    saveThumbnailsDescription: '3MF 파일에서 미리보기 이미지 추출 및 저장',
     captureFinishPhotoDescription: '인쇄 완료 시 프린터 카메라로 사진 촬영. Bambuddy는 인쇄 중 짧은 타임랩스를 기록하여 베드가 내려가기 전 순간에서 사진을 가져올 수 있도록 합니다. 이 인쇄에 대해 타임랩스를 활성화한 경우 타임랩스 파일이 보관되며, 그렇지 않으면 사진 촬영 후 자동으로 삭제됩니다.',
     captureFinishPhotoDescription: '인쇄 완료 시 프린터 카메라로 사진 촬영. Bambuddy는 인쇄 중 짧은 타임랩스를 기록하여 베드가 내려가기 전 순간에서 사진을 가져올 수 있도록 합니다. 이 인쇄에 대해 타임랩스를 활성화한 경우 타임랩스 파일이 보관되며, 그렇지 않으면 사진 촬영 후 자동으로 삭제됩니다.',
     finishPhotoRestorePlate: '완료 사진을 위해 베드 올리기',
     finishPhotoRestorePlate: '완료 사진을 위해 베드 올리기',
     finishPhotoRestorePlateDescription: '프린터는 인쇄가 끝나면 베드를 약 100 mm 내리므로 완성된 출력물이 카메라 화각 아래에 놓입니다. Bambuddy는 베드를 마지막 인쇄 레이어 바로 위까지 다시 올려 사진을 찍은 뒤 다시 내립니다. 출력 높이를 알 수 없거나 다른 작업이 대기 중이면 건너뜁니다.',
     finishPhotoRestorePlateDescription: '프린터는 인쇄가 끝나면 베드를 약 100 mm 내리므로 완성된 출력물이 카메라 화각 아래에 놓입니다. Bambuddy는 베드를 마지막 인쇄 레이어 바로 위까지 다시 올려 사진을 찍은 뒤 다시 내립니다. 출력 높이를 알 수 없거나 다른 작업이 대기 중이면 건너뜁니다.',

+ 0 - 4
frontend/src/i18n/locales/nl.ts

@@ -2205,8 +2205,6 @@ export default {
     upToDate: 'Je bent up-to-date',
     upToDate: 'Je bent up-to-date',
     updateAvailable: 'Update beschikbaar',
     updateAvailable: 'Update beschikbaar',
     // Notifications
     // Notifications
-    notificationLanguage: 'Taal voor meldingen',
-    notificationLanguageDescription: 'Taal voor pushmeldingen',
     bedCooledThreshold: 'Drempel voor afgekoeld bed',
     bedCooledThreshold: 'Drempel voor afgekoeld bed',
     bedCooledThresholdDescription: 'Temperatuur waaronder het bed na een afdruk als afgekoeld wordt beschouwd',
     bedCooledThresholdDescription: 'Temperatuur waaronder het bed na een afdruk als afgekoeld wordt beschouwd',
     userNotificationsEnabled: 'Gebruikersmeldingen',
     userNotificationsEnabled: 'Gebruikersmeldingen',
@@ -2333,7 +2331,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'Volgorde zijbalk',
     sidebarOrder: 'Volgorde zijbalk',
     // Camera
     // Camera
-    saveThumbnails: 'Miniaturen opslaan',
     captureFinishPhoto: 'Eindfoto vastleggen',
     captureFinishPhoto: 'Eindfoto vastleggen',
     noPrintersConfigured: 'Geen printers geconfigureerd',
     noPrintersConfigured: 'Geen printers geconfigureerd',
     // Updates
     // Updates
@@ -2877,7 +2874,6 @@ export default {
     // Archive
     // Archive
     autoArchivePrints: 'Afdrukken automatisch archiveren',
     autoArchivePrints: 'Afdrukken automatisch archiveren',
     autoArchiveDescription: '3MF-bestanden automatisch opslaan wanneer afdrukken zijn voltooid. Uit: geen enkele printer archiveert afdrukken die buiten Bambuddy zijn gestart.',
     autoArchiveDescription: '3MF-bestanden automatisch opslaan wanneer afdrukken zijn voltooid. Uit: geen enkele printer archiveert afdrukken die buiten Bambuddy zijn gestart.',
-    saveThumbnailsDescription: 'Voorbeeldafbeeldingen uit 3MF-bestanden extraheren en opslaan',
     captureFinishPhotoDescription: 'Maak een foto met de printercamera wanneer de afdruk is voltooid. Bambuddy neemt tijdens de afdruk een korte timelapse op zodat de foto kan worden genomen van het moment voordat het bed zakt; het timelapsebestand blijft behouden als je timelapse voor deze afdruk hebt ingeschakeld, anders wordt het automatisch verwijderd nadat de foto is vastgelegd.',
     captureFinishPhotoDescription: 'Maak een foto met de printercamera wanneer de afdruk is voltooid. Bambuddy neemt tijdens de afdruk een korte timelapse op zodat de foto kan worden genomen van het moment voordat het bed zakt; het timelapsebestand blijft behouden als je timelapse voor deze afdruk hebt ingeschakeld, anders wordt het automatisch verwijderd nadat de foto is vastgelegd.',
     finishPhotoRestorePlate: 'Plaat herstellen voor eindfoto',
     finishPhotoRestorePlate: 'Plaat herstellen voor eindfoto',
     finishPhotoRestorePlateDescription: 'De printer laat de bouwplaat ongeveer 100 mm zakken wanneer een afdruk eindigt, waardoor de voltooide afdruk onder het camerabeeld komt. Bambuddy brengt de plaat terug tot net boven de laatst geprinte laag, maakt de foto en laat hem daarna weer zakken. Wordt overgeslagen wanneer de afdrukhoogte onbekend is of er een andere taak in de wachtrij staat.',
     finishPhotoRestorePlateDescription: 'De printer laat de bouwplaat ongeveer 100 mm zakken wanneer een afdruk eindigt, waardoor de voltooide afdruk onder het camerabeeld komt. Bambuddy brengt de plaat terug tot net boven de laatst geprinte laag, maakt de foto en laat hem daarna weer zakken. Wordt overgeslagen wanneer de afdrukhoogte onbekend is of er een andere taak in de wachtrij staat.',

+ 0 - 4
frontend/src/i18n/locales/pt-BR.ts

@@ -2140,8 +2140,6 @@ export default {
     upToDate: 'Você está atualizado',
     upToDate: 'Você está atualizado',
     updateAvailable: 'Atualização disponível',
     updateAvailable: 'Atualização disponível',
     // Notifications
     // Notifications
-    notificationLanguage: 'Idioma das Notificações',
-    notificationLanguageDescription: 'Idioma para notificações push',
     bedCooledThreshold: 'Limite de Resfriamento da Cama',
     bedCooledThreshold: 'Limite de Resfriamento da Cama',
     bedCooledThresholdDescription: 'Temperatura abaixo da qual a cama é considerada resfriada após uma impressão',
     bedCooledThresholdDescription: 'Temperatura abaixo da qual a cama é considerada resfriada após uma impressão',
     userNotificationsEnabled: 'Notificações do Usuário',
     userNotificationsEnabled: 'Notificações do Usuário',
@@ -2268,7 +2266,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'Ordem da barra lateral',
     sidebarOrder: 'Ordem da barra lateral',
     // Camera
     // Camera
-    saveThumbnails: 'Salvar miniaturas',
     captureFinishPhoto: 'Capturar foto de conclusão',
     captureFinishPhoto: 'Capturar foto de conclusão',
     noPrintersConfigured: 'Nenhuma impressora configurada',
     noPrintersConfigured: 'Nenhuma impressora configurada',
     // Updates
     // Updates
@@ -2809,7 +2806,6 @@ export default {
     progressInTitleDescription: 'Mostra a porcentagem da impressão ativa e um anel de progresso na aba do navegador.',
     progressInTitleDescription: 'Mostra a porcentagem da impressão ativa e um anel de progresso na aba do navegador.',
     autoArchivePrints: 'Arquivar impressões automaticamente',
     autoArchivePrints: 'Arquivar impressões automaticamente',
     autoArchiveDescription: 'Salvar automaticamente arquivos 3MF quando impressões forem concluídas. Desativado: nenhuma impressora arquiva impressões iniciadas fora do Bambuddy.',
     autoArchiveDescription: 'Salvar automaticamente arquivos 3MF quando impressões forem concluídas. Desativado: nenhuma impressora arquiva impressões iniciadas fora do Bambuddy.',
-    saveThumbnailsDescription: 'Extrair e salvar imagens de pré-visualização dos arquivos 3MF',
     captureFinishPhotoDescription: 'Tirar foto da câmera da impressora quando a impressão for concluída. Bambuddy grava um timelapse curto durante a impressão para que a foto possa ser obtida do momento antes da mesa descer; o arquivo do timelapse é mantido se você habilitou o timelapse para esta impressão, caso contrário ele é excluído automaticamente após a captura da foto.',
     captureFinishPhotoDescription: 'Tirar foto da câmera da impressora quando a impressão for concluída. Bambuddy grava um timelapse curto durante a impressão para que a foto possa ser obtida do momento antes da mesa descer; o arquivo do timelapse é mantido se você habilitou o timelapse para esta impressão, caso contrário ele é excluído automaticamente após a captura da foto.',
     finishPhotoRestorePlate: 'Elevar a mesa para a foto final',
     finishPhotoRestorePlate: 'Elevar a mesa para a foto final',
     finishPhotoRestorePlateDescription: 'A impressora baixa a mesa cerca de 100 mm ao fim de uma impressão, deixando a peça pronta abaixo do enquadramento da câmera. O Bambuddy a eleva novamente até logo acima da última camada impressa, tira a foto e depois a baixa de novo. Ignorado quando a altura da impressão é desconhecida ou há outro trabalho na fila.',
     finishPhotoRestorePlateDescription: 'A impressora baixa a mesa cerca de 100 mm ao fim de uma impressão, deixando a peça pronta abaixo do enquadramento da câmera. O Bambuddy a eleva novamente até logo acima da última camada impressa, tira a foto e depois a baixa de novo. Ignorado quando a altura da impressão é desconhecida ou há outro trabalho na fila.',

+ 0 - 4
frontend/src/i18n/locales/ru.ts

@@ -2088,8 +2088,6 @@ export default {
     latestVersion: "Последняя версия",
     latestVersion: "Последняя версия",
     upToDate: "Установлена последняя версия",
     upToDate: "Установлена последняя версия",
     updateAvailable: "Доступно обновление",
     updateAvailable: "Доступно обновление",
-    notificationLanguage: "Язык уведомлений",
-    notificationLanguageDescription: "Язык push-уведомлений",
     bedCooledThreshold: "Порог остывания стола",
     bedCooledThreshold: "Порог остывания стола",
     bedCooledThresholdDescription: "Температура, ниже которой стол после печати считается остывшим",
     bedCooledThresholdDescription: "Температура, ниже которой стол после печати считается остывшим",
     userNotificationsEnabled: "Пользовательские уведомления",
     userNotificationsEnabled: "Пользовательские уведомления",
@@ -2209,7 +2207,6 @@ export default {
     allPrinters: "Все принтеры",
     allPrinters: "Все принтеры",
     noDefaultPrinter: "Без принтера по умолчанию (спрашивать каждый раз)",
     noDefaultPrinter: "Без принтера по умолчанию (спрашивать каждый раз)",
     sidebarOrder: "Порядок пунктов боковой панели",
     sidebarOrder: "Порядок пунктов боковой панели",
-    saveThumbnails: "Сохранять миниатюры",
     captureFinishPhoto: "Снимок после завершения",
     captureFinishPhoto: "Снимок после завершения",
     noPrintersConfigured: "Принтеры не настроены",
     noPrintersConfigured: "Принтеры не настроены",
     checkForUpdatesLabel: "Проверять обновления",
     checkForUpdatesLabel: "Проверять обновления",
@@ -2725,7 +2722,6 @@ export default {
     progressInTitleDescription: "Показывает процент текущей печати и кольцо прогресса во вкладке браузера.",
     progressInTitleDescription: "Показывает процент текущей печати и кольцо прогресса во вкладке браузера.",
     autoArchivePrints: "Автоматически архивировать печать",
     autoArchivePrints: "Автоматически архивировать печать",
     autoArchiveDescription: "Автоматически сохранять 3MF после завершения печати. Если выключено, ни один принтер не архивирует печать, запущенную не из Bambuddy.",
     autoArchiveDescription: "Автоматически сохранять 3MF после завершения печати. Если выключено, ни один принтер не архивирует печать, запущенную не из Bambuddy.",
-    saveThumbnailsDescription: "Извлекать и сохранять изображения предпросмотра из 3MF",
     captureFinishPhotoDescription: "Сделать снимок камерой принтера после завершения печати. Во время печати Bambuddy записывает короткий таймлапс, чтобы получить кадр до опускания стола. Если таймлапс был включён для задания, файл сохранится; иначе после получения снимка он будет автоматически удалён.",
     captureFinishPhotoDescription: "Сделать снимок камерой принтера после завершения печати. Во время печати Bambuddy записывает короткий таймлапс, чтобы получить кадр до опускания стола. Если таймлапс был включён для задания, файл сохранится; иначе после получения снимка он будет автоматически удалён.",
     finishPhotoRestorePlate: "Поднимать стол для финального снимка",
     finishPhotoRestorePlate: "Поднимать стол для финального снимка",
     finishPhotoRestorePlateDescription: "По окончании печати принтер опускает стол примерно на 100 мм, и готовая модель оказывается ниже кадра камеры. Bambuddy поднимает стол обратно чуть выше последнего напечатанного слоя, делает снимок и снова опускает его. Пропускается, если высота печати неизвестна или в очереди есть другое задание.",
     finishPhotoRestorePlateDescription: "По окончании печати принтер опускает стол примерно на 100 мм, и готовая модель оказывается ниже кадра камеры. Bambuddy поднимает стол обратно чуть выше последнего напечатанного слоя, делает снимок и снова опускает его. Пропускается, если высота печати неизвестна или в очереди есть другое задание.",

+ 0 - 4
frontend/src/i18n/locales/sv.ts

@@ -2204,8 +2204,6 @@ export default {
     upToDate: 'Du har den senaste versionen',
     upToDate: 'Du har den senaste versionen',
     updateAvailable: 'Uppdatering tillgänglig',
     updateAvailable: 'Uppdatering tillgänglig',
     // Notifications
     // Notifications
-    notificationLanguage: 'Notisspråk',
-    notificationLanguageDescription: 'Språk för push-notiser',
     bedCooledThreshold: 'Tröskelvärde för sval byggplatta',
     bedCooledThreshold: 'Tröskelvärde för sval byggplatta',
     bedCooledThresholdDescription: 'Temperatur under vilken byggplattan anses sval efter en utskrift',
     bedCooledThresholdDescription: 'Temperatur under vilken byggplattan anses sval efter en utskrift',
     userNotificationsEnabled: 'Användarnotiser',
     userNotificationsEnabled: 'Användarnotiser',
@@ -2332,7 +2330,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: 'Sidofältsordning',
     sidebarOrder: 'Sidofältsordning',
     // Camera
     // Camera
-    saveThumbnails: 'Spara minibilder',
     captureFinishPhoto: 'Ta färdig-foto',
     captureFinishPhoto: 'Ta färdig-foto',
     noPrintersConfigured: 'Inga skrivare konfigurerade',
     noPrintersConfigured: 'Inga skrivare konfigurerade',
     // Updates
     // Updates
@@ -2876,7 +2873,6 @@ export default {
     // Archive
     // Archive
     autoArchivePrints: 'Auto-arkivera utskrifter',
     autoArchivePrints: 'Auto-arkivera utskrifter',
     autoArchiveDescription: 'Spara automatiskt 3MF-filer när utskrifter slutförs. Av: ingen skrivare arkiverar utskrifter som startats utanför Bambuddy.',
     autoArchiveDescription: 'Spara automatiskt 3MF-filer när utskrifter slutförs. Av: ingen skrivare arkiverar utskrifter som startats utanför Bambuddy.',
-    saveThumbnailsDescription: 'Extrahera och spara förhandsvisningsbilder från 3MF-filer',
     captureFinishPhotoDescription: 'Ta ett foto från skrivarkameran när utskriften slutförs. Bambuddy spelar in en kort timelapse under utskriften så att fotot kan hämtas från ögonblicket innan byggplattan sänks; timelapse-filen behålls om du aktiverat timelapse för denna utskrift, annars tas den automatiskt bort efter att fotot tagits.',
     captureFinishPhotoDescription: 'Ta ett foto från skrivarkameran när utskriften slutförs. Bambuddy spelar in en kort timelapse under utskriften så att fotot kan hämtas från ögonblicket innan byggplattan sänks; timelapse-filen behålls om du aktiverat timelapse för denna utskrift, annars tas den automatiskt bort efter att fotot tagits.',
     finishPhotoRestorePlate: 'Återställ platta för foto',
     finishPhotoRestorePlate: 'Återställ platta för foto',
     finishPhotoRestorePlateDescription: 'Skrivaren sänker byggplattan cirka 100 mm när en utskrift slutförs, vilket lämnar den färdiga utskriften under kamerans bildruta. Bambuddy höjer tillbaka den precis ovanför det sista utskrivna skiktet, tar fotot och sänker den igen. Hoppas över när utskriftshöjden är okänd eller om ett annat jobb är köat.',
     finishPhotoRestorePlateDescription: 'Skrivaren sänker byggplattan cirka 100 mm när en utskrift slutförs, vilket lämnar den färdiga utskriften under kamerans bildruta. Bambuddy höjer tillbaka den precis ovanför det sista utskrivna skiktet, tar fotot och sänker den igen. Hoppas över när utskriftshöjden är okänd eller om ett annat jobb är köat.',

+ 0 - 4
frontend/src/i18n/locales/tr.ts

@@ -2188,8 +2188,6 @@ export default {
     upToDate: 'Güncelsiniz',
     upToDate: 'Güncelsiniz',
     updateAvailable: 'Güncelleme mevcut',
     updateAvailable: 'Güncelleme mevcut',
     // Bildirimler
     // Bildirimler
-    notificationLanguage: 'Bildirim Dili',
-    notificationLanguageDescription: 'Push bildirimleri için dil',
     bedCooledThreshold: 'Tabla Soğuma Eşiği',
     bedCooledThreshold: 'Tabla Soğuma Eşiği',
     bedCooledThresholdDescription: 'Bir baskıdan sonra tablanın soğumuş kabul edildiği sıcaklık',
     bedCooledThresholdDescription: 'Bir baskıdan sonra tablanın soğumuş kabul edildiği sıcaklık',
     userNotificationsEnabled: 'Kullanıcı Bildirimleri',
     userNotificationsEnabled: 'Kullanıcı Bildirimleri',
@@ -2316,7 +2314,6 @@ export default {
     // Kenar çubuğu
     // Kenar çubuğu
     sidebarOrder: 'Kenar çubuğu sırası',
     sidebarOrder: 'Kenar çubuğu sırası',
     // Kamera
     // Kamera
-    saveThumbnails: 'Küçük resimleri kaydet',
     captureFinishPhoto: 'Bitiş fotoğrafı çek',
     captureFinishPhoto: 'Bitiş fotoğrafı çek',
     noPrintersConfigured: 'Yapılandırılmış yazıcı yok',
     noPrintersConfigured: 'Yapılandırılmış yazıcı yok',
     // Arşiv ayarları
     // Arşiv ayarları
@@ -2860,7 +2857,6 @@ export default {
     // Arşiv
     // Arşiv
     autoArchivePrints: 'Baskıları otomatik arşivle',
     autoArchivePrints: 'Baskıları otomatik arşivle',
     autoArchiveDescription: 'Baskılar tamamlandığında 3MF dosyalarını otomatik olarak kaydet. Kapalıyken hiçbir yazıcı Bambuddy dışında başlatılan baskıları arşivlemez.',
     autoArchiveDescription: 'Baskılar tamamlandığında 3MF dosyalarını otomatik olarak kaydet. Kapalıyken hiçbir yazıcı Bambuddy dışında başlatılan baskıları arşivlemez.',
-    saveThumbnailsDescription: '3MF dosyalarından önizleme görüntülerini çıkar ve kaydet',
     captureFinishPhotoDescription: 'Baskı tamamlandığında yazıcı kamerasından bir fotoğraf çek. Bambuddy, baskı sırasında kısa bir zaman atlamalı kayıt yapar, böylece fotoğraf tabla inmeden önceki andan alınabilir. Bu baskı için zaman atlamalı kaydı etkinleştirdiyseniz dosya saklanır, aksi takdirde fotoğraf çekildikten sonra otomatik olarak silinir.',
     captureFinishPhotoDescription: 'Baskı tamamlandığında yazıcı kamerasından bir fotoğraf çek. Bambuddy, baskı sırasında kısa bir zaman atlamalı kayıt yapar, böylece fotoğraf tabla inmeden önceki andan alınabilir. Bu baskı için zaman atlamalı kaydı etkinleştirdiyseniz dosya saklanır, aksi takdirde fotoğraf çekildikten sonra otomatik olarak silinir.',
     finishPhotoRestorePlate: 'Bitiş fotoğrafı için tablayı yükselt',
     finishPhotoRestorePlate: 'Bitiş fotoğrafı için tablayı yükselt',
     finishPhotoRestorePlateDescription: 'Yazıcı, baskı bittiğinde tablayı yaklaşık 100 mm aşağı indirir ve tamamlanmış baskı kameranın çerçevesinin altında kalır. Bambuddy tablayı son basılan katmanın hemen üzerine geri kaldırır, fotoğrafı çeker ve ardından tekrar indirir. Baskı yüksekliği bilinmiyorsa veya kuyrukta başka bir iş varsa atlanır.',
     finishPhotoRestorePlateDescription: 'Yazıcı, baskı bittiğinde tablayı yaklaşık 100 mm aşağı indirir ve tamamlanmış baskı kameranın çerçevesinin altında kalır. Bambuddy tablayı son basılan katmanın hemen üzerine geri kaldırır, fotoğrafı çeker ve ardından tekrar indirir. Baskı yüksekliği bilinmiyorsa veya kuyrukta başka bir iş varsa atlanır.',

+ 0 - 4
frontend/src/i18n/locales/uk.ts

@@ -2203,8 +2203,6 @@ export default {
     upToDate: "У вас установлено останню версію",
     upToDate: "У вас установлено останню версію",
     updateAvailable: "Доступне оновлення",
     updateAvailable: "Доступне оновлення",
     // Notifications
     // Notifications
-    notificationLanguage: "Мова сповіщень",
-    notificationLanguageDescription: "Мова для push-повідомлень",
     bedCooledThreshold: "Поріг охолодження столу",
     bedCooledThreshold: "Поріг охолодження столу",
     bedCooledThresholdDescription: "Температура, нижче якої стіл вважається охолодженим після друку",
     bedCooledThresholdDescription: "Температура, нижче якої стіл вважається охолодженим після друку",
     userNotificationsEnabled: "Сповіщення користувача",
     userNotificationsEnabled: "Сповіщення користувача",
@@ -2331,7 +2329,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: "Порядок бічної панелі",
     sidebarOrder: "Порядок бічної панелі",
     // Camera
     // Camera
-    saveThumbnails: "Зберегти мініатюри",
     captureFinishPhoto: "Зробити фото після завершення",
     captureFinishPhoto: "Зробити фото після завершення",
     noPrintersConfigured: "Принтери не налаштовані",
     noPrintersConfigured: "Принтери не налаштовані",
     // Updates
     // Updates
@@ -2874,7 +2871,6 @@ export default {
     // Archive
     // Archive
     autoArchivePrints: "Автоматично архівувати друки",
     autoArchivePrints: "Автоматично архівувати друки",
     autoArchiveDescription: "Автоматично зберігати файли 3MF після завершення друку. Якщо вимкнено, жоден принтер не архівує друк, запущений не з Bambuddy.",
     autoArchiveDescription: "Автоматично зберігати файли 3MF після завершення друку. Якщо вимкнено, жоден принтер не архівує друк, запущений не з Bambuddy.",
-    saveThumbnailsDescription: "Витягніть і збережіть зображення попереднього перегляду з файлів 3MF.",
     captureFinishPhotoDescription: "Зробіть фотографію з камери принтера після завершення друку. Bambuddy записує короткий проміжок часу під час друку, щоб фотографію можна було отримати з моменту, коли стіл опускається; файл уповільненої зйомки зберігається, якщо ви ввімкнули уповільнену зйомку для цього друку, інакше він автоматично видаляється після зйомки фотографії.",
     captureFinishPhotoDescription: "Зробіть фотографію з камери принтера після завершення друку. Bambuddy записує короткий проміжок часу під час друку, щоб фотографію можна було отримати з моменту, коли стіл опускається; файл уповільненої зйомки зберігається, якщо ви ввімкнули уповільнену зйомку для цього друку, інакше він автоматично видаляється після зйомки фотографії.",
     finishPhotoRestorePlate: "Піднімати стіл для фінального знімка",
     finishPhotoRestorePlate: "Піднімати стіл для фінального знімка",
     finishPhotoRestorePlateDescription: "Після завершення друку принтер опускає стіл приблизно на 100 мм, і готова модель опиняється нижче кадру камери. Bambuddy піднімає стіл назад трохи вище останнього надрукованого шару, робить знімок і знову опускає його. Пропускається, якщо висота друку невідома або в черзі є інше завдання.",
     finishPhotoRestorePlateDescription: "Після завершення друку принтер опускає стіл приблизно на 100 мм, і готова модель опиняється нижче кадру камери. Bambuddy піднімає стіл назад трохи вище останнього надрукованого шару, робить знімок і знову опускає його. Пропускається, якщо висота друку невідома або в черзі є інше завдання.",

+ 0 - 4
frontend/src/i18n/locales/zh-CN.ts

@@ -2185,8 +2185,6 @@ export default {
     upToDate: '已是最新版本',
     upToDate: '已是最新版本',
     updateAvailable: '有可用更新',
     updateAvailable: '有可用更新',
     // Notifications
     // Notifications
-    notificationLanguage: '通知语言',
-    notificationLanguageDescription: '推送通知的语言',
     bedCooledThreshold: '热床冷却阈值',
     bedCooledThreshold: '热床冷却阈值',
     bedCooledThresholdDescription: '打印后热床被视为已冷却的温度',
     bedCooledThresholdDescription: '打印后热床被视为已冷却的温度',
     userNotificationsEnabled: '用户通知',
     userNotificationsEnabled: '用户通知',
@@ -2313,7 +2311,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: '侧边栏顺序',
     sidebarOrder: '侧边栏顺序',
     // Camera
     // Camera
-    saveThumbnails: '保存缩略图',
     captureFinishPhoto: '拍摄完成照片',
     captureFinishPhoto: '拍摄完成照片',
     noPrintersConfigured: '未配置打印机',
     noPrintersConfigured: '未配置打印机',
     // Updates
     // Updates
@@ -2854,7 +2851,6 @@ export default {
     progressInTitleDescription: '在浏览器标签页中显示当前打印的百分比和进度环。',
     progressInTitleDescription: '在浏览器标签页中显示当前打印的百分比和进度环。',
     autoArchivePrints: '自动归档打印',
     autoArchivePrints: '自动归档打印',
     autoArchiveDescription: '打印完成时自动保存3MF文件。关闭时,所有打印机都不会归档在 Bambuddy 之外启动的打印。',
     autoArchiveDescription: '打印完成时自动保存3MF文件。关闭时,所有打印机都不会归档在 Bambuddy 之外启动的打印。',
-    saveThumbnailsDescription: '从3MF文件中提取并保存预览图像',
     captureFinishPhotoDescription: '打印完成时从打印机摄像头拍照。Bambuddy 会在打印期间录制一段短延时摄影,以便从热床下降前的瞬间获取照片;如果您为本次打印启用了延时摄影,文件将保留,否则会在拍照完成后自动删除。',
     captureFinishPhotoDescription: '打印完成时从打印机摄像头拍照。Bambuddy 会在打印期间录制一段短延时摄影,以便从热床下降前的瞬间获取照片;如果您为本次打印启用了延时摄影,文件将保留,否则会在拍照完成后自动删除。',
     finishPhotoRestorePlate: '为完成照片抬升热床',
     finishPhotoRestorePlate: '为完成照片抬升热床',
     finishPhotoRestorePlateDescription: '打印结束时打印机会将热床下降约 100 mm,使完成的模型落在相机取景范围之下。Bambuddy 会将热床抬回到最后一层打印高度略上方,拍摄照片后再次下降。若打印高度未知或队列中还有其他任务,则跳过此步骤。',
     finishPhotoRestorePlateDescription: '打印结束时打印机会将热床下降约 100 mm,使完成的模型落在相机取景范围之下。Bambuddy 会将热床抬回到最后一层打印高度略上方,拍摄照片后再次下降。若打印高度未知或队列中还有其他任务,则跳过此步骤。',

+ 0 - 4
frontend/src/i18n/locales/zh-TW.ts

@@ -2185,8 +2185,6 @@ export default {
     upToDate: '已是最新版本',
     upToDate: '已是最新版本',
     updateAvailable: '有可用更新',
     updateAvailable: '有可用更新',
     // Notifications
     // Notifications
-    notificationLanguage: '通知語言',
-    notificationLanguageDescription: '推送通知的語言',
     bedCooledThreshold: '熱床冷卻閾值',
     bedCooledThreshold: '熱床冷卻閾值',
     bedCooledThresholdDescription: '列印後熱床被視為已冷卻的溫度',
     bedCooledThresholdDescription: '列印後熱床被視為已冷卻的溫度',
     userNotificationsEnabled: '使用者通知',
     userNotificationsEnabled: '使用者通知',
@@ -2313,7 +2311,6 @@ export default {
     // Sidebar
     // Sidebar
     sidebarOrder: '側邊欄順序',
     sidebarOrder: '側邊欄順序',
     // Camera
     // Camera
-    saveThumbnails: '儲存縮圖',
     captureFinishPhoto: '拍攝完成照片',
     captureFinishPhoto: '拍攝完成照片',
     noPrintersConfigured: '未設定印表機',
     noPrintersConfigured: '未設定印表機',
     // Updates
     // Updates
@@ -2854,7 +2851,6 @@ export default {
     progressInTitleDescription: '在瀏覽器分頁中顯示目前列印的百分比和進度環。',
     progressInTitleDescription: '在瀏覽器分頁中顯示目前列印的百分比和進度環。',
     autoArchivePrints: '自動歸檔列印',
     autoArchivePrints: '自動歸檔列印',
     autoArchiveDescription: '列印完成時自動儲存3MF檔案。關閉時,所有印表機都不會歸檔在 Bambuddy 之外啟動的列印。',
     autoArchiveDescription: '列印完成時自動儲存3MF檔案。關閉時,所有印表機都不會歸檔在 Bambuddy 之外啟動的列印。',
-    saveThumbnailsDescription: '從3MF檔案中提取並儲存預覽影像',
     captureFinishPhotoDescription: '列印完成時從印表機攝影機拍照。Bambuddy 會在列印期間錄製一段短縮時攝影,以便從熱床下降前的瞬間取得照片;如果您為本次列印啟用了縮時攝影,檔案將保留,否則會在拍照完成後自動刪除。',
     captureFinishPhotoDescription: '列印完成時從印表機攝影機拍照。Bambuddy 會在列印期間錄製一段短縮時攝影,以便從熱床下降前的瞬間取得照片;如果您為本次列印啟用了縮時攝影,檔案將保留,否則會在拍照完成後自動刪除。',
     finishPhotoRestorePlate: '為完成照片抬升熱床',
     finishPhotoRestorePlate: '為完成照片抬升熱床',
     finishPhotoRestorePlateDescription: '列印結束時印表機會將熱床下降約 100 mm,使完成的模型落在相機取景範圍之下。Bambuddy 會將熱床抬回到最後一層列印高度略上方,拍攝照片後再次下降。若列印高度未知或佇列中還有其他任務,則跳過此步驟。',
     finishPhotoRestorePlateDescription: '列印結束時印表機會將熱床下降約 100 mm,使完成的模型落在相機取景範圍之下。Bambuddy 會將熱床抬回到最後一層列印高度略上方,拍攝照片後再次下降。若列印高度未知或佇列中還有其他任務,則跳過此步驟。',

+ 0 - 44
frontend/src/pages/SettingsPage.tsx

@@ -1254,7 +1254,6 @@ export function SettingsPage() {
     // Check if there are actual changes
     // Check if there are actual changes
     const hasChanges =
     const hasChanges =
       baseline.auto_archive !== localSettings.auto_archive ||
       baseline.auto_archive !== localSettings.auto_archive ||
-      baseline.save_thumbnails !== localSettings.save_thumbnails ||
       baseline.capture_finish_photo !== localSettings.capture_finish_photo ||
       baseline.capture_finish_photo !== localSettings.capture_finish_photo ||
       (baseline.finish_photo_restore_plate ?? true) !== (localSettings.finish_photo_restore_plate ?? true) ||
       (baseline.finish_photo_restore_plate ?? true) !== (localSettings.finish_photo_restore_plate ?? true) ||
       baseline.default_filament_cost !== localSettings.default_filament_cost ||
       baseline.default_filament_cost !== localSettings.default_filament_cost ||
@@ -1270,7 +1269,6 @@ export function SettingsPage() {
       (baseline.announcements_enabled ?? true) !== (localSettings.announcements_enabled ?? true) ||
       (baseline.announcements_enabled ?? true) !== (localSettings.announcements_enabled ?? true) ||
       (baseline.announcements_all_users ?? false) !== (localSettings.announcements_all_users ?? false) ||
       (baseline.announcements_all_users ?? false) !== (localSettings.announcements_all_users ?? false) ||
       (baseline.local_login_enabled ?? true) !== (localSettings.local_login_enabled ?? true) ||
       (baseline.local_login_enabled ?? true) !== (localSettings.local_login_enabled ?? true) ||
-      baseline.notification_language !== localSettings.notification_language ||
       (baseline.bed_cooled_threshold ?? 35) !== (localSettings.bed_cooled_threshold ?? 35) ||
       (baseline.bed_cooled_threshold ?? 35) !== (localSettings.bed_cooled_threshold ?? 35) ||
       baseline.ams_humidity_good !== localSettings.ams_humidity_good ||
       baseline.ams_humidity_good !== localSettings.ams_humidity_good ||
       baseline.ams_humidity_fair !== localSettings.ams_humidity_fair ||
       baseline.ams_humidity_fair !== localSettings.ams_humidity_fair ||
@@ -1376,7 +1374,6 @@ export function SettingsPage() {
       // Only send the fields we manage on this page (exclude virtual_printer_* which are managed separately)
       // Only send the fields we manage on this page (exclude virtual_printer_* which are managed separately)
       const settingsToSave: AppSettingsUpdate = {
       const settingsToSave: AppSettingsUpdate = {
         auto_archive: localSettings.auto_archive,
         auto_archive: localSettings.auto_archive,
-        save_thumbnails: localSettings.save_thumbnails,
         capture_finish_photo: localSettings.capture_finish_photo,
         capture_finish_photo: localSettings.capture_finish_photo,
         // #2547: `?? true` mirrors the toggle's own default, so an install
         // #2547: `?? true` mirrors the toggle's own default, so an install
         // whose settings payload predates this field saves what the user is
         // whose settings payload predates this field saves what the user is
@@ -1400,7 +1397,6 @@ export function SettingsPage() {
         announcements_enabled: localSettings.announcements_enabled ?? true,
         announcements_enabled: localSettings.announcements_enabled ?? true,
         announcements_all_users: localSettings.announcements_all_users ?? false,
         announcements_all_users: localSettings.announcements_all_users ?? false,
         local_login_enabled: localSettings.local_login_enabled,
         local_login_enabled: localSettings.local_login_enabled,
-        notification_language: localSettings.notification_language,
         bed_cooled_threshold: localSettings.bed_cooled_threshold,
         bed_cooled_threshold: localSettings.bed_cooled_threshold,
         ams_humidity_good: localSettings.ams_humidity_good,
         ams_humidity_good: localSettings.ams_humidity_good,
         ams_humidity_fair: localSettings.ams_humidity_fair,
         ams_humidity_fair: localSettings.ams_humidity_fair,
@@ -2115,23 +2111,6 @@ export function SettingsPage() {
                   <div className="w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green"></div>
                   <div className="w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green"></div>
                 </label>
                 </label>
               </div>
               </div>
-              <div className="flex items-center justify-between">
-                <div>
-                  <p className="text-white">{t('settings.saveThumbnails')}</p>
-                  <p className="text-sm text-bambu-gray">
-                    {t('settings.saveThumbnailsDescription')}
-                  </p>
-                </div>
-                <label className="relative inline-flex items-center cursor-pointer">
-                  <input
-                    type="checkbox"
-                    checked={localSettings.save_thumbnails}
-                    onChange={(e) => updateSetting('save_thumbnails', e.target.checked)}
-                    className="sr-only peer"
-                  />
-                  <div className="w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green"></div>
-                </label>
-              </div>
               <div className="flex items-center justify-between">
               <div className="flex items-center justify-between">
                 <div>
                 <div>
                   <p className="text-white">{t('settings.captureFinishPhoto')}</p>
                   <p className="text-white">{t('settings.captureFinishPhoto')}</p>
@@ -4092,29 +4071,6 @@ export function SettingsPage() {
               </div>
               </div>
             </div>
             </div>
 
 
-            {/* Notification Language Setting */}
-            <Card className="mb-4">
-              <CardContent className="py-3">
-                <div className="flex items-center justify-between">
-                  <div>
-                    <p className="text-white text-sm font-medium">{t('settings.notificationLanguage')}</p>
-                    <p className="text-xs text-bambu-gray">{t('settings.notificationLanguageDescription')}</p>
-                  </div>
-                  <select
-                    value={localSettings.notification_language || 'en'}
-                    onChange={(e) => updateSetting('notification_language', e.target.value)}
-                    className="px-2 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:outline-none focus:ring-1 focus:ring-bambu-green"
-                  >
-                    {availableLanguages.map((lang) => (
-                      <option key={lang.code} value={lang.code}>
-                        {lang.nativeName}
-                      </option>
-                    ))}
-                  </select>
-                </div>
-              </CardContent>
-            </Card>
-
             {/* Bed Cooled Threshold Setting */}
             {/* Bed Cooled Threshold Setting */}
             <Card className="mb-4">
             <Card className="mb-4">
               <CardContent className="py-3">
               <CardContent className="py-3">