diff --git a/CHANGELOG.fr.md b/CHANGELOG.fr.md index e6b4701..0563e56 100644 --- a/CHANGELOG.fr.md +++ b/CHANGELOG.fr.md @@ -5,6 +5,9 @@ ### Ajouté - CI : nouveau workflow `check.yml` qui exécute `cargo check`/`cargo test` et le build frontend sur chaque push de branche et PR, détectant les erreurs avant le merge plutôt qu'au moment de la release (#60) +### Modifié +- Les mises à jour automatiques sont maintenant réservées à l'édition Base ; l'édition Gratuite affiche un message invitant à activer une licence (#48) + ## [0.6.7] - 2026-03-29 ### Modifié diff --git a/CHANGELOG.md b/CHANGELOG.md index 391185b..088a5c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ ### Added - CI: new `check.yml` workflow runs `cargo check`/`cargo test` and the frontend build on every branch push and PR, catching errors before merge instead of waiting for the release tag (#60) +### Changed +- Automatic updates are now gated behind the Base edition entitlement; the Free edition shows an upgrade hint instead of fetching updates (#48) + ## [0.6.7] - 2026-03-29 ### Changed diff --git a/src/components/shared/ErrorPage.tsx b/src/components/shared/ErrorPage.tsx index 630c95b..0cfbca8 100644 --- a/src/components/shared/ErrorPage.tsx +++ b/src/components/shared/ErrorPage.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; import { AlertTriangle, ChevronDown, ChevronUp, RefreshCw, Download, Mail, Bug } from "lucide-react"; import { check } from "@tauri-apps/plugin-updater"; +import { invoke } from "@tauri-apps/api/core"; interface ErrorPageProps { error?: string; @@ -10,7 +11,7 @@ interface ErrorPageProps { export default function ErrorPage({ error }: ErrorPageProps) { const { t } = useTranslation(); const [showDetails, setShowDetails] = useState(false); - const [updateStatus, setUpdateStatus] = useState<"idle" | "checking" | "available" | "upToDate" | "error">("idle"); + const [updateStatus, setUpdateStatus] = useState<"idle" | "checking" | "available" | "upToDate" | "notEntitled" | "error">("idle"); const [updateVersion, setUpdateVersion] = useState(null); const [updateError, setUpdateError] = useState(null); @@ -18,6 +19,13 @@ export default function ErrorPage({ error }: ErrorPageProps) { setUpdateStatus("checking"); setUpdateError(null); try { + const allowed = await invoke("check_entitlement", { + feature: "auto-update", + }); + if (!allowed) { + setUpdateStatus("notEntitled"); + return; + } const update = await check(); if (update) { setUpdateStatus("available"); @@ -89,6 +97,11 @@ export default function ErrorPage({ error }: ErrorPageProps) { {t("error.upToDate")}

)} + {updateStatus === "notEntitled" && ( +

+ {t("error.updateNotEntitled")} +

+ )} {updateStatus === "error" && updateError && (

{updateError}

)} diff --git a/src/hooks/useUpdater.ts b/src/hooks/useUpdater.ts index b694786..9bf9f34 100644 --- a/src/hooks/useUpdater.ts +++ b/src/hooks/useUpdater.ts @@ -1,6 +1,7 @@ import { useReducer, useCallback, useRef } from "react"; import { check, type Update } from "@tauri-apps/plugin-updater"; import { relaunch } from "@tauri-apps/plugin-process"; +import { invoke } from "@tauri-apps/api/core"; type UpdateStatus = | "idle" @@ -10,6 +11,7 @@ type UpdateStatus = | "downloading" | "readyToInstall" | "installing" + | "notEntitled" | "error"; interface UpdaterState { @@ -29,6 +31,7 @@ type UpdaterAction = | { type: "DOWNLOAD_PROGRESS"; downloaded: number; contentLength: number | null } | { type: "READY_TO_INSTALL" } | { type: "INSTALLING" } + | { type: "NOT_ENTITLED" } | { type: "ERROR"; error: string }; const initialState: UpdaterState = { @@ -56,6 +59,8 @@ function reducer(state: UpdaterState, action: UpdaterAction): UpdaterState { return { ...state, status: "readyToInstall", error: null }; case "INSTALLING": return { ...state, status: "installing", error: null }; + case "NOT_ENTITLED": + return { ...state, status: "notEntitled", error: null }; case "ERROR": return { ...state, status: "error", error: action.error }; } @@ -68,6 +73,16 @@ export function useUpdater() { const checkForUpdate = useCallback(async () => { dispatch({ type: "CHECK_START" }); try { + // Auto-updates are gated behind the entitlements module (Issue #46/#48). + // The check is centralized server-side via `check_entitlement` so the + // tier→feature mapping lives in one place. + const allowed = await invoke("check_entitlement", { + feature: "auto-update", + }); + if (!allowed) { + dispatch({ type: "NOT_ENTITLED" }); + return; + } const update = await check(); if (update) { updateRef.current = update; diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index e7b4011..f078f6b 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -436,7 +436,8 @@ "installing": "Installing...", "error": "Update failed", "retryButton": "Retry", - "releaseNotes": "What's New" + "releaseNotes": "What's New", + "notEntitled": "Automatic updates are available with the Base edition. Activate a license to enable them." }, "dataManagement": { "title": "Data Management", @@ -827,6 +828,7 @@ "checkUpdate": "Check for updates", "updateAvailable": "Update available: v{{version}}", "upToDate": "The application is up to date", + "updateNotEntitled": "Automatic updates are available with the Base edition.", "contactUs": "Contact us", "contactEmail": "Send an email to", "reportIssue": "Report an issue" diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index af3cba4..51a9b40 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -436,7 +436,8 @@ "installing": "Installation en cours...", "error": "Erreur lors de la mise à jour", "retryButton": "Réessayer", - "releaseNotes": "Nouveautés" + "releaseNotes": "Nouveautés", + "notEntitled": "Les mises à jour automatiques sont disponibles avec l'édition Base. Activez une licence pour les utiliser." }, "dataManagement": { "title": "Gestion des données", @@ -827,6 +828,7 @@ "checkUpdate": "Vérifier les mises à jour", "updateAvailable": "Mise à jour disponible : v{{version}}", "upToDate": "L'application est à jour", + "updateNotEntitled": "Les mises à jour automatiques sont disponibles avec l'édition Base.", "contactUs": "Nous contacter", "contactEmail": "Envoyez un email à", "reportIssue": "Signaler un problème" diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 6e56b16..b567155 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -155,6 +155,14 @@ export default function SettingsPage() { )} + {/* not entitled (free edition) */} + {state.status === "notEntitled" && ( +
+ +

{t("settings.updates.notEntitled")}

+
+ )} + {/* up to date */} {state.status === "upToDate" && (