diff --git a/package.json b/package.json index 13530b0..ab322df 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "rapport", "private": true, - "version": "0.8.1", + "version": "0.8.2", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 77034a1..211947d 100755 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2880,7 +2880,7 @@ dependencies = [ [[package]] name = "rapport" -version = "0.8.0" +version = "0.8.1" dependencies = [ "log", "serde", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e16c8f6..3995a61 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rapport" -version = "0.8.1" +version = "0.8.2" description = "Rapport — Studio-Management für Architekturbüros" authors = ["Karim Gabriele Varano "] license = "AGPL-3.0-or-later" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 8e66689..509dbbe 100755 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "productName": "RAPPORT PRE-RELEASE", - "version": "0.8.1", + "version": "0.8.2", "identifier": "com.karimgabrielevarano.rapport", "build": { "frontendDist": "../dist", diff --git a/src/App.jsx b/src/App.jsx index 42a5984..65cc816 100755 --- a/src/App.jsx +++ b/src/App.jsx @@ -297,8 +297,8 @@ export default function App() { const [modal, setModal] = useState(null); const [printContent, setPrintContent] = useState(null); const [darkMode, setDarkMode] = useState(() => localStorage.getItem("rapport_dark") === "1"); - const [showChangelog, setShowChangelog] = useState(() => localStorage.getItem("rapport_changelog_seen") !== "0.8.1"); - const [changelogVersion, setChangelogVersion] = useState("0.8.1"); + const [showChangelog, setShowChangelog] = useState(() => localStorage.getItem("rapport_changelog_seen") !== "0.8.2"); + const [changelogVersion, setChangelogVersion] = useState("0.8.2"); const [showAbout, setShowAbout] = useState(false); const [navOpen, setNavOpen] = useState(false); const [expandedNav, setExpandedNav] = useState(new Set(["buchhaltung"])); @@ -456,19 +456,21 @@ export default function App() { // Erst-Screen einer frischen Installation: «Lokal oder Cloud?». // Sichtbar solange der User die Wahl noch nicht getroffen hat UND es keine // lokalen Daten gibt. Sobald er gewählt hat, übernimmt der jeweilige Wizard. + // UpdateNotifier wird in allen Pre-Login-Screens mitgerendert, damit ein + // hängender Setup-Wizard sich via Auto-Update selbst befreien kann. const hasChosenBackend = localStorage.getItem("rapport_backend_chosen") === "1"; if (!hasChosenBackend && isNewInstall && !data.settings.setupCompleted && !currentUser) { - return ; + return <>; } // Setup- und Migrations-Screens sind LocalStorage-Spezifika. Im Cloud-Modus // erfolgt Erst-Einrichtung über den Init-Dialog im Login. if (!isCloudBackend && isNewInstall && !data.settings.setupCompleted) { - return ; + return <>; } if (!isCloudBackend && !localStorage.getItem("rapport_v0_5_migrated")) { - return ; + return <>; } // Passwort-Reset hat höchste Priorität — User kommt von Mail-Link @@ -493,12 +495,21 @@ export default function App() { // Cloud + Instanz ist leer (0 Studios) → mehrseitiger Setup-Wizard. // Cloud + Studios vorhanden → klassischer Login. + // UpdateNotifier wird hier auch gerendert, damit der Auto-Update-Check auch + // ohne Login läuft (sonst kommt man bei einem fehlerhaften Setup-Screen nie + // an ein neueres Build, das den Bug fixt). if (!currentUser) { if (isCloudBackend && cloudStudios !== null && cloudStudios.length === 0) { const cloudUrl = localStorage.getItem("rapport_cloud_url") || ""; - return ; + return <> + + + ; } - return ; + return <> + + + ; } if (printContent) { @@ -771,8 +782,8 @@ export default function App() {
- +
} @@ -837,6 +848,13 @@ export default function App() { {showChangelog && (() => { const CHANGELOGS = { + "0.8.2": { + items: [ + ["Selbstheilung für hängende 0.8.0-Installationen", "Wer von 0.7 auf 0.8 geupdated hat und in den Cloud-Setup-Wizard geschoben wurde, kommt mit 0.8.2 automatisch zurück in seinen Lokal-Modus. Der Auto-Recovery-Code erkennt: Cloud-Modus gesetzt + lokale Daten vorhanden + keine Cloud-Anmeldung → Cloud-Konfiguration wird zurückgenommen, alle Daten bleiben erhalten."], + ["Auto-Update auch ohne Login", "Bisher prüfte Rapport erst nach dem Login auf Updates — wer in einem fehlerhaften Setup-Bildschirm hing, kam nicht an den Bugfix. Jetzt läuft der Update-Check auch im «Lokal oder Cloud»-Wizard, im Login-Screen und im Cloud-Setup."], + ["Tauri ohne fest eingebaute Server-IP", "Die Desktop-App enthält keine vorkonfigurierte Cloud-Adresse mehr. Wer Cloud nutzen will, gibt die Server-Adresse beim Login aktiv ein — kein automatisches Vorausfüllen mit irrelevanten IPs."], + ], + }, "0.8.1": { items: [ ["Update-Fix", "Behebt einen Fehler beim Upgrade von 0.7 auf 0.8: Lokal-Installationen wurden ungewollt in den Cloud-Modus geschoben und der Cloud-Setup-Wizard angezeigt, obwohl bereits lokale Daten vorhanden waren. Die App prüft jetzt vor einem automatischen Modus-Wechsel, ob lokale Daten existieren — und in Tauri-Installationen wird der Modus nie implizit gesetzt."], @@ -919,7 +937,7 @@ export default function App() { }, }; const versions = Object.keys(CHANGELOGS); - const current = CHANGELOGS[changelogVersion] || CHANGELOGS["0.8.1"]; + const current = CHANGELOGS[changelogVersion] || CHANGELOGS["0.8.2"]; return (
@@ -948,7 +966,7 @@ export default function App() { ))}
-
@@ -963,7 +981,7 @@ export default function App() {
ÜBER RAPPORT
Rapport
-
Alpha 0.8.1 · Studio-Management für Architekturbüros
+
Alpha 0.8.2 · Studio-Management für Architekturbüros
LIZENZ
diff --git a/src/storage/adapter.js b/src/storage/adapter.js index ff3b1dd..52e93a7 100644 --- a/src/storage/adapter.js +++ b/src/storage/adapter.js @@ -46,22 +46,37 @@ export class LocalStorageAdapter { } function createAdapter() { - // Build-time-Default für Web-Deploy: wenn eine Production-Build VITE_SUPABASE_URL - // gesetzt hat (z.B. via .env.production) und der User noch nichts gewählt hat, - // wird Cloud automatisch der Modus. Damit landet ein Browser, der app.rapport.kgva.ch - // öffnet, direkt im Cloud-Login (bzw. Init-Dialog wenn Server leer). - // - // Bewusst NICHT auto-cloud wenn: - // - Dev-Build (`npm run dev`) — User sieht weiterhin BackendChoice - // - lokale Daten existieren (würde bestehenden Lokal-User auf Cloud zwingen - // und seine Daten unsichtbar machen) — Bug bei 0.7→0.8-Upgrade - // - Tauri-Desktop-App (Tauri-User sollen immer aktiv wählen, nicht implizit - // aufgrund von .env.production eines Builds umgehauen werden) - if (typeof localStorage !== "undefined" && import.meta.env.PROD) { - const envUrl = import.meta.env.VITE_SUPABASE_URL; + const isTauri = typeof window !== "undefined" && !!window.__TAURI_INTERNALS__; + // Build-time-URL nur für Web-Deploy gültig. Tauri-Builds ignorieren den + // eingebrannten Wert — Desktop-User geben die Server-URL aktiv ein. + // Der Anon-Key bleibt aus dem Build, weil er pro Cloud-Instanz konstant ist + // (kein User-Geheimnis, sondern Public-Konfig). + const envUrl = isTauri ? null : import.meta.env.VITE_SUPABASE_URL; + const envKey = import.meta.env.VITE_SUPABASE_ANON_KEY; + + if (typeof localStorage !== "undefined") { + // ── Auto-Recovery für 0.8.0-Upgrade-Bug ────────────────────────────── + // 0.8.0 hat Cloud-Modus ungewollt gesetzt bei Lokal-Usern (siehe 0.8.1 + // CHANGELOG). 0.8.1 verhindert das nur prospektiv, behebt aber den + // bestehenden Cloud-State nicht. Hier räumen wir nachträglich auf: + // Cloud-Modus gesetzt + lokale Daten vorhanden + keine Cloud-Session + // → Cloud-State löschen, User landet im BackendChoice oder Lokal-Modus. + const RECOVERY_MARKER = "rapport_080_recovery"; + const backend = localStorage.getItem("rapport_backend"); const hasLocalData = !!localStorage.getItem(STORAGE_KEY); - const isTauri = typeof window !== "undefined" && !!window.__TAURI_INTERNALS__; - if (envUrl && !localStorage.getItem("rapport_backend_chosen") && !hasLocalData && !isTauri) { + const hasCloudSession = !!localStorage.getItem("rapport_supabase_session"); + if (backend === "cloud" && hasLocalData && !hasCloudSession && !localStorage.getItem(RECOVERY_MARKER)) { + console.warn("Auto-Recovery: Cloud-Modus gesetzt, aber Lokal-Daten vorhanden und kein Cloud-Login — räume Cloud-State auf."); + localStorage.removeItem("rapport_backend"); + localStorage.removeItem("rapport_backend_chosen"); + localStorage.removeItem("rapport_cloud_url"); + localStorage.setItem(RECOVERY_MARKER, "1"); + } + + // ── Auto-Cloud-Default für Web-Deploy ──────────────────────────────── + // Nur wenn keine lokalen Daten existieren und der Browser auf einer + // konfigurierten Web-Instanz landet (envUrl aus build). + if (import.meta.env.PROD && envUrl && !localStorage.getItem("rapport_backend_chosen") && !hasLocalData) { localStorage.setItem("rapport_backend_chosen", "1"); localStorage.setItem("rapport_backend", "cloud"); if (!localStorage.getItem("rapport_cloud_url")) { @@ -73,14 +88,15 @@ function createAdapter() { const backend = (typeof localStorage !== "undefined" && localStorage.getItem("rapport_backend")) || "local"; if (backend === "cloud") { - const url = import.meta.env.VITE_SUPABASE_URL; - const key = import.meta.env.VITE_SUPABASE_ANON_KEY; - if (!url || !key) { - console.warn("rapport_backend=cloud, aber VITE_SUPABASE_URL/ANON_KEY fehlen — Fallback auf LocalStorage."); + // URL kommt bevorzugt aus localStorage (vom User eingegeben). Tauri hat + // gar keine env-URL; Web-Build hat sie ggf. als Fallback. + const url = (typeof localStorage !== "undefined" && localStorage.getItem("rapport_cloud_url")) || envUrl; + if (!url || !envKey) { + console.warn("rapport_backend=cloud, aber URL oder ANON_KEY fehlen — Fallback auf LocalStorage."); return new LocalStorageAdapter(); } console.info("Storage-Adapter: SupabaseAdapter aktiv (URL:", url + ")"); - return new SupabaseAdapter(url, key); + return new SupabaseAdapter(url, envKey); } return new LocalStorageAdapter(); } diff --git a/src/views/BackendChoice.jsx b/src/views/BackendChoice.jsx index 15bfa85..407c5da 100644 --- a/src/views/BackendChoice.jsx +++ b/src/views/BackendChoice.jsx @@ -7,7 +7,10 @@ import React from "react"; // Lokal → bestehender Setup.jsx // Cloud → Login mit Init-Modus oder Login-Modus (je nach Studio-Vorhandensein) -const envCloudUrl = import.meta.env.VITE_SUPABASE_URL || ""; +// Tauri-User geben die Server-URL immer aktiv ein. Build-time-URL ist nur +// für Web-Deploy gedacht (z.B. app.rapport.kgva.ch → 127.0.0.1:54321 lokal). +const isTauri = typeof window !== "undefined" && !!window.__TAURI_INTERNALS__; +const envCloudUrl = isTauri ? "" : (import.meta.env.VITE_SUPABASE_URL || ""); export default function BackendChoice() { const pick = (backend, cloudUrl = "") => {